19948a064SJiri Pirko // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
29948a064SJiri Pirko /* Copyright (c) 2015-2018 Mellanox Technologies. All rights reserved */
356ade8feSJiri Pirko
456ade8feSJiri Pirko #include <linux/kernel.h>
556ade8feSJiri Pirko #include <linux/module.h>
656ade8feSJiri Pirko #include <linux/types.h>
71d20d23cSJiri Pirko #include <linux/pci.h>
856ade8feSJiri Pirko #include <linux/netdevice.h>
956ade8feSJiri Pirko #include <linux/etherdevice.h>
1056ade8feSJiri Pirko #include <linux/ethtool.h>
1156ade8feSJiri Pirko #include <linux/slab.h>
1256ade8feSJiri Pirko #include <linux/device.h>
1356ade8feSJiri Pirko #include <linux/skbuff.h>
1456ade8feSJiri Pirko #include <linux/if_vlan.h>
1556ade8feSJiri Pirko #include <linux/if_bridge.h>
1656ade8feSJiri Pirko #include <linux/workqueue.h>
1756ade8feSJiri Pirko #include <linux/jiffies.h>
1856ade8feSJiri Pirko #include <linux/bitops.h>
197f71eb46SIdo Schimmel #include <linux/list.h>
2080bedf1aSIdo Schimmel #include <linux/notifier.h>
2190183b98SIdo Schimmel #include <linux/dcbnl.h>
2299724c18SIdo Schimmel #include <linux/inetdevice.h>
23c1f2c6d0SIdo Schimmel #include <linux/netlink.h>
24fa73989fSIdo Schimmel #include <linux/jhash.h>
25c8fc10dcSJiri Pirko #include <linux/log2.h>
261b9fc42eSIdo Schimmel #include <linux/refcount.h>
271b9fc42eSIdo Schimmel #include <linux/rhashtable.h>
2856ade8feSJiri Pirko #include <net/switchdev.h>
29763b4b70SYotam Gigi #include <net/pkt_cls.h>
30e7322638SJiri Pirko #include <net/netevent.h>
315ea1237fSArkadi Sharshevsky #include <net/addrconf.h>
3224157bc6SDanielle Ratson #include <linux/ptp_classify.h>
3356ade8feSJiri Pirko
3456ade8feSJiri Pirko #include "spectrum.h"
351d20d23cSJiri Pirko #include "pci.h"
3656ade8feSJiri Pirko #include "core.h"
371b1c6c1aSVadim Pasternak #include "core_env.h"
3856ade8feSJiri Pirko #include "reg.h"
3956ade8feSJiri Pirko #include "port.h"
4056ade8feSJiri Pirko #include "trap.h"
4156ade8feSJiri Pirko #include "txheader.h"
42ff7b0d27SArkadi Sharshevsky #include "spectrum_cnt.h"
43230ead01SArkadi Sharshevsky #include "spectrum_dpipe.h"
44d3b939b8SYotam Gigi #include "spectrum_acl_flex_actions.h"
45a629ef21SPetr Machata #include "spectrum_span.h"
46412cd2adSShalom Toledo #include "spectrum_ptp.h"
4703484e49SIdo Schimmel #include "spectrum_trap.h"
4856ade8feSJiri Pirko
498b5f555bSJiri Pirko #define MLXSW_SP_FWREV_MINOR 2010
508b5f555bSJiri Pirko #define MLXSW_SP_FWREV_SUBMINOR 1006
518b5f555bSJiri Pirko
52abfd6182SJiri Pirko #define MLXSW_SP1_FWREV_MAJOR 13
53c86d62ccSJiri Pirko #define MLXSW_SP1_FWREV_CAN_RESET_MINOR 1702
54abfd6182SJiri Pirko
55abfd6182SJiri Pirko static const struct mlxsw_fw_rev mlxsw_sp1_fw_rev = {
56abfd6182SJiri Pirko .major = MLXSW_SP1_FWREV_MAJOR,
578b5f555bSJiri Pirko .minor = MLXSW_SP_FWREV_MINOR,
588b5f555bSJiri Pirko .subminor = MLXSW_SP_FWREV_SUBMINOR,
59c86d62ccSJiri Pirko .can_reset_minor = MLXSW_SP1_FWREV_CAN_RESET_MINOR,
60abfd6182SJiri Pirko };
61abfd6182SJiri Pirko
62abfd6182SJiri Pirko #define MLXSW_SP1_FW_FILENAME \
63abfd6182SJiri Pirko "mellanox/mlxsw_spectrum-" __stringify(MLXSW_SP1_FWREV_MAJOR) \
648b5f555bSJiri Pirko "." __stringify(MLXSW_SP_FWREV_MINOR) \
658b5f555bSJiri Pirko "." __stringify(MLXSW_SP_FWREV_SUBMINOR) ".mfa2"
666b742199SYotam Gigi
67a72afb68SIdo Schimmel #define MLXSW_SP2_FWREV_MAJOR 29
68a72afb68SIdo Schimmel
69a72afb68SIdo Schimmel static const struct mlxsw_fw_rev mlxsw_sp2_fw_rev = {
70a72afb68SIdo Schimmel .major = MLXSW_SP2_FWREV_MAJOR,
718b5f555bSJiri Pirko .minor = MLXSW_SP_FWREV_MINOR,
728b5f555bSJiri Pirko .subminor = MLXSW_SP_FWREV_SUBMINOR,
73a72afb68SIdo Schimmel };
74a72afb68SIdo Schimmel
75a72afb68SIdo Schimmel #define MLXSW_SP2_FW_FILENAME \
76a72afb68SIdo Schimmel "mellanox/mlxsw_spectrum2-" __stringify(MLXSW_SP2_FWREV_MAJOR) \
778b5f555bSJiri Pirko "." __stringify(MLXSW_SP_FWREV_MINOR) \
788b5f555bSJiri Pirko "." __stringify(MLXSW_SP_FWREV_SUBMINOR) ".mfa2"
79a72afb68SIdo Schimmel
8034639fa3SPetr Machata #define MLXSW_SP3_FWREV_MAJOR 30
8134639fa3SPetr Machata
8234639fa3SPetr Machata static const struct mlxsw_fw_rev mlxsw_sp3_fw_rev = {
8334639fa3SPetr Machata .major = MLXSW_SP3_FWREV_MAJOR,
848b5f555bSJiri Pirko .minor = MLXSW_SP_FWREV_MINOR,
858b5f555bSJiri Pirko .subminor = MLXSW_SP_FWREV_SUBMINOR,
8634639fa3SPetr Machata };
8734639fa3SPetr Machata
8834639fa3SPetr Machata #define MLXSW_SP3_FW_FILENAME \
8934639fa3SPetr Machata "mellanox/mlxsw_spectrum3-" __stringify(MLXSW_SP3_FWREV_MAJOR) \
908b5f555bSJiri Pirko "." __stringify(MLXSW_SP_FWREV_MINOR) \
918b5f555bSJiri Pirko "." __stringify(MLXSW_SP_FWREV_SUBMINOR) ".mfa2"
9234639fa3SPetr Machata
93b217127eSJiri Pirko #define MLXSW_SP_LINECARDS_INI_BUNDLE_FILENAME \
94b217127eSJiri Pirko "mellanox/lc_ini_bundle_" \
95b217127eSJiri Pirko __stringify(MLXSW_SP_FWREV_MINOR) "_" \
96b217127eSJiri Pirko __stringify(MLXSW_SP_FWREV_SUBMINOR) ".bin"
97b217127eSJiri Pirko
98c3ab4354SJiri Pirko static const char mlxsw_sp1_driver_name[] = "mlxsw_spectrum";
99c3ab4354SJiri Pirko static const char mlxsw_sp2_driver_name[] = "mlxsw_spectrum2";
100da382875SJiri Pirko static const char mlxsw_sp3_driver_name[] = "mlxsw_spectrum3";
10147354021SAmit Cohen static const char mlxsw_sp4_driver_name[] = "mlxsw_spectrum4";
10256ade8feSJiri Pirko
1039329b816SPetr Machata static const unsigned char mlxsw_sp1_mac_mask[ETH_ALEN] = {
1049329b816SPetr Machata 0xff, 0xff, 0xff, 0xff, 0xfc, 0x00
1059329b816SPetr Machata };
1069329b816SPetr Machata static const unsigned char mlxsw_sp2_mac_mask[ETH_ALEN] = {
1079329b816SPetr Machata 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00
1089329b816SPetr Machata };
1099329b816SPetr Machata
11056ade8feSJiri Pirko /* tx_hdr_version
11156ade8feSJiri Pirko * Tx header version.
11256ade8feSJiri Pirko * Must be set to 1.
11356ade8feSJiri Pirko */
11456ade8feSJiri Pirko MLXSW_ITEM32(tx, hdr, version, 0x00, 28, 4);
11556ade8feSJiri Pirko
11656ade8feSJiri Pirko /* tx_hdr_ctl
11756ade8feSJiri Pirko * Packet control type.
11856ade8feSJiri Pirko * 0 - Ethernet control (e.g. EMADs, LACP)
11956ade8feSJiri Pirko * 1 - Ethernet data
12056ade8feSJiri Pirko */
12156ade8feSJiri Pirko MLXSW_ITEM32(tx, hdr, ctl, 0x00, 26, 2);
12256ade8feSJiri Pirko
12356ade8feSJiri Pirko /* tx_hdr_proto
12456ade8feSJiri Pirko * Packet protocol type. Must be set to 1 (Ethernet).
12556ade8feSJiri Pirko */
12656ade8feSJiri Pirko MLXSW_ITEM32(tx, hdr, proto, 0x00, 21, 3);
12756ade8feSJiri Pirko
12856ade8feSJiri Pirko /* tx_hdr_rx_is_router
12956ade8feSJiri Pirko * Packet is sent from the router. Valid for data packets only.
13056ade8feSJiri Pirko */
13156ade8feSJiri Pirko MLXSW_ITEM32(tx, hdr, rx_is_router, 0x00, 19, 1);
13256ade8feSJiri Pirko
13356ade8feSJiri Pirko /* tx_hdr_fid_valid
13456ade8feSJiri Pirko * Indicates if the 'fid' field is valid and should be used for
13556ade8feSJiri Pirko * forwarding lookup. Valid for data packets only.
13656ade8feSJiri Pirko */
13756ade8feSJiri Pirko MLXSW_ITEM32(tx, hdr, fid_valid, 0x00, 16, 1);
13856ade8feSJiri Pirko
13956ade8feSJiri Pirko /* tx_hdr_swid
14056ade8feSJiri Pirko * Switch partition ID. Must be set to 0.
14156ade8feSJiri Pirko */
14256ade8feSJiri Pirko MLXSW_ITEM32(tx, hdr, swid, 0x00, 12, 3);
14356ade8feSJiri Pirko
14456ade8feSJiri Pirko /* tx_hdr_control_tclass
14556ade8feSJiri Pirko * Indicates if the packet should use the control TClass and not one
14656ade8feSJiri Pirko * of the data TClasses.
14756ade8feSJiri Pirko */
14856ade8feSJiri Pirko MLXSW_ITEM32(tx, hdr, control_tclass, 0x00, 6, 1);
14956ade8feSJiri Pirko
15056ade8feSJiri Pirko /* tx_hdr_etclass
15156ade8feSJiri Pirko * Egress TClass to be used on the egress device on the egress port.
15256ade8feSJiri Pirko */
15356ade8feSJiri Pirko MLXSW_ITEM32(tx, hdr, etclass, 0x00, 0, 4);
15456ade8feSJiri Pirko
15556ade8feSJiri Pirko /* tx_hdr_port_mid
15656ade8feSJiri Pirko * Destination local port for unicast packets.
15756ade8feSJiri Pirko * Destination multicast ID for multicast packets.
15856ade8feSJiri Pirko *
15956ade8feSJiri Pirko * Control packets are directed to a specific egress port, while data
16056ade8feSJiri Pirko * packets are transmitted through the CPU port (0) into the switch partition,
16156ade8feSJiri Pirko * where forwarding rules are applied.
16256ade8feSJiri Pirko */
16356ade8feSJiri Pirko MLXSW_ITEM32(tx, hdr, port_mid, 0x04, 16, 16);
16456ade8feSJiri Pirko
16556ade8feSJiri Pirko /* tx_hdr_fid
16656ade8feSJiri Pirko * Forwarding ID used for L2 forwarding lookup. Valid only if 'fid_valid' is
16756ade8feSJiri Pirko * set, otherwise calculated based on the packet's VID using VID to FID mapping.
16856ade8feSJiri Pirko * Valid for data packets only.
16956ade8feSJiri Pirko */
17081016180SDanielle Ratson MLXSW_ITEM32(tx, hdr, fid, 0x08, 16, 16);
17156ade8feSJiri Pirko
17256ade8feSJiri Pirko /* tx_hdr_type
17356ade8feSJiri Pirko * 0 - Data packets
17456ade8feSJiri Pirko * 6 - Control packets
17556ade8feSJiri Pirko */
17656ade8feSJiri Pirko MLXSW_ITEM32(tx, hdr, type, 0x0C, 0, 4);
17756ade8feSJiri Pirko
mlxsw_sp_flow_counter_get(struct mlxsw_sp * mlxsw_sp,unsigned int counter_index,u64 * packets,u64 * bytes)1781abcbcc2SArkadi Sharshevsky int mlxsw_sp_flow_counter_get(struct mlxsw_sp *mlxsw_sp,
1791abcbcc2SArkadi Sharshevsky unsigned int counter_index, u64 *packets,
1801abcbcc2SArkadi Sharshevsky u64 *bytes)
1811abcbcc2SArkadi Sharshevsky {
1821abcbcc2SArkadi Sharshevsky char mgpc_pl[MLXSW_REG_MGPC_LEN];
1831abcbcc2SArkadi Sharshevsky int err;
1841abcbcc2SArkadi Sharshevsky
1851abcbcc2SArkadi Sharshevsky mlxsw_reg_mgpc_pack(mgpc_pl, counter_index, MLXSW_REG_MGPC_OPCODE_NOP,
1866bba7e20SArkadi Sharshevsky MLXSW_REG_FLOW_COUNTER_SET_TYPE_PACKETS_BYTES);
1871abcbcc2SArkadi Sharshevsky err = mlxsw_reg_query(mlxsw_sp->core, MLXSW_REG(mgpc), mgpc_pl);
1881abcbcc2SArkadi Sharshevsky if (err)
1891abcbcc2SArkadi Sharshevsky return err;
1907cfcbc75SArkadi Sharshevsky if (packets)
1911abcbcc2SArkadi Sharshevsky *packets = mlxsw_reg_mgpc_packet_counter_get(mgpc_pl);
1927cfcbc75SArkadi Sharshevsky if (bytes)
1931abcbcc2SArkadi Sharshevsky *bytes = mlxsw_reg_mgpc_byte_counter_get(mgpc_pl);
1941abcbcc2SArkadi Sharshevsky return 0;
1951abcbcc2SArkadi Sharshevsky }
1961abcbcc2SArkadi Sharshevsky
mlxsw_sp_flow_counter_clear(struct mlxsw_sp * mlxsw_sp,unsigned int counter_index)1971abcbcc2SArkadi Sharshevsky static int mlxsw_sp_flow_counter_clear(struct mlxsw_sp *mlxsw_sp,
1981abcbcc2SArkadi Sharshevsky unsigned int counter_index)
1991abcbcc2SArkadi Sharshevsky {
2001abcbcc2SArkadi Sharshevsky char mgpc_pl[MLXSW_REG_MGPC_LEN];
2011abcbcc2SArkadi Sharshevsky
2021abcbcc2SArkadi Sharshevsky mlxsw_reg_mgpc_pack(mgpc_pl, counter_index, MLXSW_REG_MGPC_OPCODE_CLEAR,
2036bba7e20SArkadi Sharshevsky MLXSW_REG_FLOW_COUNTER_SET_TYPE_PACKETS_BYTES);
2041abcbcc2SArkadi Sharshevsky return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(mgpc), mgpc_pl);
2051abcbcc2SArkadi Sharshevsky }
2061abcbcc2SArkadi Sharshevsky
mlxsw_sp_flow_counter_alloc(struct mlxsw_sp * mlxsw_sp,unsigned int * p_counter_index)2071abcbcc2SArkadi Sharshevsky int mlxsw_sp_flow_counter_alloc(struct mlxsw_sp *mlxsw_sp,
2081abcbcc2SArkadi Sharshevsky unsigned int *p_counter_index)
2091abcbcc2SArkadi Sharshevsky {
2101abcbcc2SArkadi Sharshevsky int err;
2111abcbcc2SArkadi Sharshevsky
2121abcbcc2SArkadi Sharshevsky err = mlxsw_sp_counter_alloc(mlxsw_sp, MLXSW_SP_COUNTER_SUB_POOL_FLOW,
2131abcbcc2SArkadi Sharshevsky p_counter_index);
2141abcbcc2SArkadi Sharshevsky if (err)
2151abcbcc2SArkadi Sharshevsky return err;
2161abcbcc2SArkadi Sharshevsky err = mlxsw_sp_flow_counter_clear(mlxsw_sp, *p_counter_index);
2171abcbcc2SArkadi Sharshevsky if (err)
2181abcbcc2SArkadi Sharshevsky goto err_counter_clear;
2191abcbcc2SArkadi Sharshevsky return 0;
2201abcbcc2SArkadi Sharshevsky
2211abcbcc2SArkadi Sharshevsky err_counter_clear:
2221abcbcc2SArkadi Sharshevsky mlxsw_sp_counter_free(mlxsw_sp, MLXSW_SP_COUNTER_SUB_POOL_FLOW,
2231abcbcc2SArkadi Sharshevsky *p_counter_index);
2241abcbcc2SArkadi Sharshevsky return err;
2251abcbcc2SArkadi Sharshevsky }
2261abcbcc2SArkadi Sharshevsky
mlxsw_sp_flow_counter_free(struct mlxsw_sp * mlxsw_sp,unsigned int counter_index)2271abcbcc2SArkadi Sharshevsky void mlxsw_sp_flow_counter_free(struct mlxsw_sp *mlxsw_sp,
2281abcbcc2SArkadi Sharshevsky unsigned int counter_index)
2291abcbcc2SArkadi Sharshevsky {
2301abcbcc2SArkadi Sharshevsky mlxsw_sp_counter_free(mlxsw_sp, MLXSW_SP_COUNTER_SUB_POOL_FLOW,
2311abcbcc2SArkadi Sharshevsky counter_index);
2321abcbcc2SArkadi Sharshevsky }
2331abcbcc2SArkadi Sharshevsky
mlxsw_sp_txhdr_construct(struct sk_buff * skb,const struct mlxsw_tx_info * tx_info)23424157bc6SDanielle Ratson void mlxsw_sp_txhdr_construct(struct sk_buff *skb,
23556ade8feSJiri Pirko const struct mlxsw_tx_info *tx_info)
23656ade8feSJiri Pirko {
23756ade8feSJiri Pirko char *txhdr = skb_push(skb, MLXSW_TXHDR_LEN);
23856ade8feSJiri Pirko
23956ade8feSJiri Pirko memset(txhdr, 0, MLXSW_TXHDR_LEN);
24056ade8feSJiri Pirko
24156ade8feSJiri Pirko mlxsw_tx_hdr_version_set(txhdr, MLXSW_TXHDR_VERSION_1);
24256ade8feSJiri Pirko mlxsw_tx_hdr_ctl_set(txhdr, MLXSW_TXHDR_ETH_CTL);
24356ade8feSJiri Pirko mlxsw_tx_hdr_proto_set(txhdr, MLXSW_TXHDR_PROTO_ETH);
24456ade8feSJiri Pirko mlxsw_tx_hdr_swid_set(txhdr, 0);
24556ade8feSJiri Pirko mlxsw_tx_hdr_control_tclass_set(txhdr, 1);
24656ade8feSJiri Pirko mlxsw_tx_hdr_port_mid_set(txhdr, tx_info->local_port);
24756ade8feSJiri Pirko mlxsw_tx_hdr_type_set(txhdr, MLXSW_TXHDR_TYPE_CONTROL);
24856ade8feSJiri Pirko }
24956ade8feSJiri Pirko
25024157bc6SDanielle Ratson int
mlxsw_sp_txhdr_ptp_data_construct(struct mlxsw_core * mlxsw_core,struct mlxsw_sp_port * mlxsw_sp_port,struct sk_buff * skb,const struct mlxsw_tx_info * tx_info)25124157bc6SDanielle Ratson mlxsw_sp_txhdr_ptp_data_construct(struct mlxsw_core *mlxsw_core,
25224157bc6SDanielle Ratson struct mlxsw_sp_port *mlxsw_sp_port,
25324157bc6SDanielle Ratson struct sk_buff *skb,
25424157bc6SDanielle Ratson const struct mlxsw_tx_info *tx_info)
25524157bc6SDanielle Ratson {
25624157bc6SDanielle Ratson char *txhdr;
25724157bc6SDanielle Ratson u16 max_fid;
25824157bc6SDanielle Ratson int err;
25924157bc6SDanielle Ratson
26024157bc6SDanielle Ratson if (skb_cow_head(skb, MLXSW_TXHDR_LEN)) {
26124157bc6SDanielle Ratson err = -ENOMEM;
26224157bc6SDanielle Ratson goto err_skb_cow_head;
26324157bc6SDanielle Ratson }
26424157bc6SDanielle Ratson
26524157bc6SDanielle Ratson if (!MLXSW_CORE_RES_VALID(mlxsw_core, FID)) {
26624157bc6SDanielle Ratson err = -EIO;
26724157bc6SDanielle Ratson goto err_res_valid;
26824157bc6SDanielle Ratson }
26924157bc6SDanielle Ratson max_fid = MLXSW_CORE_RES_GET(mlxsw_core, FID);
27024157bc6SDanielle Ratson
27124157bc6SDanielle Ratson txhdr = skb_push(skb, MLXSW_TXHDR_LEN);
27224157bc6SDanielle Ratson memset(txhdr, 0, MLXSW_TXHDR_LEN);
27324157bc6SDanielle Ratson
27424157bc6SDanielle Ratson mlxsw_tx_hdr_version_set(txhdr, MLXSW_TXHDR_VERSION_1);
27524157bc6SDanielle Ratson mlxsw_tx_hdr_proto_set(txhdr, MLXSW_TXHDR_PROTO_ETH);
27624157bc6SDanielle Ratson mlxsw_tx_hdr_rx_is_router_set(txhdr, true);
27724157bc6SDanielle Ratson mlxsw_tx_hdr_fid_valid_set(txhdr, true);
27824157bc6SDanielle Ratson mlxsw_tx_hdr_fid_set(txhdr, max_fid + tx_info->local_port - 1);
27924157bc6SDanielle Ratson mlxsw_tx_hdr_type_set(txhdr, MLXSW_TXHDR_TYPE_DATA);
28024157bc6SDanielle Ratson return 0;
28124157bc6SDanielle Ratson
28224157bc6SDanielle Ratson err_res_valid:
28324157bc6SDanielle Ratson err_skb_cow_head:
28424157bc6SDanielle Ratson this_cpu_inc(mlxsw_sp_port->pcpu_stats->tx_dropped);
28524157bc6SDanielle Ratson dev_kfree_skb_any(skb);
28624157bc6SDanielle Ratson return err;
28724157bc6SDanielle Ratson }
28824157bc6SDanielle Ratson
mlxsw_sp_skb_requires_ts(struct sk_buff * skb)28924157bc6SDanielle Ratson static bool mlxsw_sp_skb_requires_ts(struct sk_buff *skb)
29024157bc6SDanielle Ratson {
29124157bc6SDanielle Ratson unsigned int type;
29224157bc6SDanielle Ratson
29324157bc6SDanielle Ratson if (!(skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP))
29424157bc6SDanielle Ratson return false;
29524157bc6SDanielle Ratson
29624157bc6SDanielle Ratson type = ptp_classify_raw(skb);
29724157bc6SDanielle Ratson return !!ptp_parse_header(skb, type);
29824157bc6SDanielle Ratson }
29924157bc6SDanielle Ratson
mlxsw_sp_txhdr_handle(struct mlxsw_core * mlxsw_core,struct mlxsw_sp_port * mlxsw_sp_port,struct sk_buff * skb,const struct mlxsw_tx_info * tx_info)30024157bc6SDanielle Ratson static int mlxsw_sp_txhdr_handle(struct mlxsw_core *mlxsw_core,
30124157bc6SDanielle Ratson struct mlxsw_sp_port *mlxsw_sp_port,
30224157bc6SDanielle Ratson struct sk_buff *skb,
30324157bc6SDanielle Ratson const struct mlxsw_tx_info *tx_info)
30424157bc6SDanielle Ratson {
30524157bc6SDanielle Ratson struct mlxsw_sp *mlxsw_sp = mlxsw_core_driver_priv(mlxsw_core);
30624157bc6SDanielle Ratson
30724157bc6SDanielle Ratson /* In Spectrum-2 and Spectrum-3, PTP events that require a time stamp
30824157bc6SDanielle Ratson * need special handling and cannot be transmitted as regular control
30924157bc6SDanielle Ratson * packets.
31024157bc6SDanielle Ratson */
31124157bc6SDanielle Ratson if (unlikely(mlxsw_sp_skb_requires_ts(skb)))
31224157bc6SDanielle Ratson return mlxsw_sp->ptp_ops->txhdr_construct(mlxsw_core,
31324157bc6SDanielle Ratson mlxsw_sp_port, skb,
31424157bc6SDanielle Ratson tx_info);
31524157bc6SDanielle Ratson
31624157bc6SDanielle Ratson if (skb_cow_head(skb, MLXSW_TXHDR_LEN)) {
31724157bc6SDanielle Ratson this_cpu_inc(mlxsw_sp_port->pcpu_stats->tx_dropped);
31824157bc6SDanielle Ratson dev_kfree_skb_any(skb);
31924157bc6SDanielle Ratson return -ENOMEM;
32024157bc6SDanielle Ratson }
32124157bc6SDanielle Ratson
32224157bc6SDanielle Ratson mlxsw_sp_txhdr_construct(skb, tx_info);
32324157bc6SDanielle Ratson return 0;
32424157bc6SDanielle Ratson }
32524157bc6SDanielle Ratson
mlxsw_sp_stp_spms_state(u8 state)326541e1159SPetr Machata enum mlxsw_reg_spms_state mlxsw_sp_stp_spms_state(u8 state)
327fe9ccc78SIdo Schimmel {
328fe9ccc78SIdo Schimmel switch (state) {
329fe9ccc78SIdo Schimmel case BR_STATE_FORWARDING:
330541e1159SPetr Machata return MLXSW_REG_SPMS_STATE_FORWARDING;
331fe9ccc78SIdo Schimmel case BR_STATE_LEARNING:
332541e1159SPetr Machata return MLXSW_REG_SPMS_STATE_LEARNING;
333df561f66SGustavo A. R. Silva case BR_STATE_LISTENING:
334df561f66SGustavo A. R. Silva case BR_STATE_DISABLED:
335fe9ccc78SIdo Schimmel case BR_STATE_BLOCKING:
336541e1159SPetr Machata return MLXSW_REG_SPMS_STATE_DISCARDING;
337fe9ccc78SIdo Schimmel default:
338fe9ccc78SIdo Schimmel BUG();
339fe9ccc78SIdo Schimmel }
340541e1159SPetr Machata }
341541e1159SPetr Machata
mlxsw_sp_port_vid_stp_set(struct mlxsw_sp_port * mlxsw_sp_port,u16 vid,u8 state)342541e1159SPetr Machata int mlxsw_sp_port_vid_stp_set(struct mlxsw_sp_port *mlxsw_sp_port, u16 vid,
343541e1159SPetr Machata u8 state)
344541e1159SPetr Machata {
345541e1159SPetr Machata enum mlxsw_reg_spms_state spms_state = mlxsw_sp_stp_spms_state(state);
346541e1159SPetr Machata struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
347541e1159SPetr Machata char *spms_pl;
348541e1159SPetr Machata int err;
349fe9ccc78SIdo Schimmel
350fe9ccc78SIdo Schimmel spms_pl = kmalloc(MLXSW_REG_SPMS_LEN, GFP_KERNEL);
351fe9ccc78SIdo Schimmel if (!spms_pl)
352fe9ccc78SIdo Schimmel return -ENOMEM;
353fe9ccc78SIdo Schimmel mlxsw_reg_spms_pack(spms_pl, mlxsw_sp_port->local_port);
354fe9ccc78SIdo Schimmel mlxsw_reg_spms_vid_pack(spms_pl, vid, spms_state);
355fe9ccc78SIdo Schimmel
356fe9ccc78SIdo Schimmel err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(spms), spms_pl);
357fe9ccc78SIdo Schimmel kfree(spms_pl);
358fe9ccc78SIdo Schimmel return err;
359fe9ccc78SIdo Schimmel }
360fe9ccc78SIdo Schimmel
mlxsw_sp_base_mac_get(struct mlxsw_sp * mlxsw_sp)36156ade8feSJiri Pirko static int mlxsw_sp_base_mac_get(struct mlxsw_sp *mlxsw_sp)
36256ade8feSJiri Pirko {
3635b090740SElad Raz char spad_pl[MLXSW_REG_SPAD_LEN] = {0};
36456ade8feSJiri Pirko int err;
36556ade8feSJiri Pirko
36656ade8feSJiri Pirko err = mlxsw_reg_query(mlxsw_sp->core, MLXSW_REG(spad), spad_pl);
36756ade8feSJiri Pirko if (err)
36856ade8feSJiri Pirko return err;
36956ade8feSJiri Pirko mlxsw_reg_spad_base_mac_memcpy_from(spad_pl, mlxsw_sp->base_mac);
37056ade8feSJiri Pirko return 0;
37156ade8feSJiri Pirko }
37256ade8feSJiri Pirko
mlxsw_sp_port_admin_status_set(struct mlxsw_sp_port * mlxsw_sp_port,bool is_up)373614d509aSAmit Cohen int mlxsw_sp_port_admin_status_set(struct mlxsw_sp_port *mlxsw_sp_port,
37456ade8feSJiri Pirko bool is_up)
37556ade8feSJiri Pirko {
37656ade8feSJiri Pirko struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
37756ade8feSJiri Pirko char paos_pl[MLXSW_REG_PAOS_LEN];
37856ade8feSJiri Pirko
37956ade8feSJiri Pirko mlxsw_reg_paos_pack(paos_pl, mlxsw_sp_port->local_port,
38056ade8feSJiri Pirko is_up ? MLXSW_PORT_ADMIN_STATUS_UP :
38156ade8feSJiri Pirko MLXSW_PORT_ADMIN_STATUS_DOWN);
38256ade8feSJiri Pirko return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(paos), paos_pl);
38356ade8feSJiri Pirko }
38456ade8feSJiri Pirko
mlxsw_sp_port_dev_addr_set(struct mlxsw_sp_port * mlxsw_sp_port,const unsigned char * addr)38556ade8feSJiri Pirko static int mlxsw_sp_port_dev_addr_set(struct mlxsw_sp_port *mlxsw_sp_port,
38654612b4aSJakub Kicinski const unsigned char *addr)
38756ade8feSJiri Pirko {
38856ade8feSJiri Pirko struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
38956ade8feSJiri Pirko char ppad_pl[MLXSW_REG_PPAD_LEN];
39056ade8feSJiri Pirko
39156ade8feSJiri Pirko mlxsw_reg_ppad_pack(ppad_pl, true, mlxsw_sp_port->local_port);
39256ade8feSJiri Pirko mlxsw_reg_ppad_mac_memcpy_to(ppad_pl, addr);
39356ade8feSJiri Pirko return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(ppad), ppad_pl);
39456ade8feSJiri Pirko }
39556ade8feSJiri Pirko
mlxsw_sp_port_dev_addr_init(struct mlxsw_sp_port * mlxsw_sp_port)39656ade8feSJiri Pirko static int mlxsw_sp_port_dev_addr_init(struct mlxsw_sp_port *mlxsw_sp_port)
39756ade8feSJiri Pirko {
39856ade8feSJiri Pirko struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
39956ade8feSJiri Pirko
400be755054SJakub Kicinski eth_hw_addr_gen(mlxsw_sp_port->dev, mlxsw_sp->base_mac,
401be755054SJakub Kicinski mlxsw_sp_port->local_port);
402be755054SJakub Kicinski return mlxsw_sp_port_dev_addr_set(mlxsw_sp_port,
403be755054SJakub Kicinski mlxsw_sp_port->dev->dev_addr);
40456ade8feSJiri Pirko }
40556ade8feSJiri Pirko
mlxsw_sp_port_max_mtu_get(struct mlxsw_sp_port * mlxsw_sp_port,int * p_max_mtu)4062ecf87aeSPetr Machata static int mlxsw_sp_port_max_mtu_get(struct mlxsw_sp_port *mlxsw_sp_port, int *p_max_mtu)
40756ade8feSJiri Pirko {
40856ade8feSJiri Pirko struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
40956ade8feSJiri Pirko char pmtu_pl[MLXSW_REG_PMTU_LEN];
41056ade8feSJiri Pirko int err;
41156ade8feSJiri Pirko
41256ade8feSJiri Pirko mlxsw_reg_pmtu_pack(pmtu_pl, mlxsw_sp_port->local_port, 0);
41356ade8feSJiri Pirko err = mlxsw_reg_query(mlxsw_sp->core, MLXSW_REG(pmtu), pmtu_pl);
41456ade8feSJiri Pirko if (err)
41556ade8feSJiri Pirko return err;
41656ade8feSJiri Pirko
4172ecf87aeSPetr Machata *p_max_mtu = mlxsw_reg_pmtu_max_mtu_get(pmtu_pl);
4182ecf87aeSPetr Machata return 0;
4192ecf87aeSPetr Machata }
4202ecf87aeSPetr Machata
mlxsw_sp_port_mtu_set(struct mlxsw_sp_port * mlxsw_sp_port,u16 mtu)4212ecf87aeSPetr Machata static int mlxsw_sp_port_mtu_set(struct mlxsw_sp_port *mlxsw_sp_port, u16 mtu)
4222ecf87aeSPetr Machata {
4232ecf87aeSPetr Machata struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
4242ecf87aeSPetr Machata char pmtu_pl[MLXSW_REG_PMTU_LEN];
4252ecf87aeSPetr Machata
4262ecf87aeSPetr Machata mtu += MLXSW_TXHDR_LEN + ETH_HLEN;
4272ecf87aeSPetr Machata if (mtu > mlxsw_sp_port->max_mtu)
42856ade8feSJiri Pirko return -EINVAL;
42956ade8feSJiri Pirko
43056ade8feSJiri Pirko mlxsw_reg_pmtu_pack(pmtu_pl, mlxsw_sp_port->local_port, mtu);
43156ade8feSJiri Pirko return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(pmtu), pmtu_pl);
43256ade8feSJiri Pirko }
43356ade8feSJiri Pirko
mlxsw_sp_port_swid_set(struct mlxsw_sp * mlxsw_sp,u16 local_port,u8 swid)434fec23861SJiri Pirko static int mlxsw_sp_port_swid_set(struct mlxsw_sp *mlxsw_sp,
435c934757dSAmit Cohen u16 local_port, u8 swid)
43656ade8feSJiri Pirko {
4375b153859SIdo Schimmel char pspa_pl[MLXSW_REG_PSPA_LEN];
43856ade8feSJiri Pirko
439fec23861SJiri Pirko mlxsw_reg_pspa_pack(pspa_pl, swid, local_port);
4405b153859SIdo Schimmel return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(pspa), pspa_pl);
44156ade8feSJiri Pirko }
44256ade8feSJiri Pirko
mlxsw_sp_port_vp_mode_set(struct mlxsw_sp_port * mlxsw_sp_port,bool enable)443a1107487SIdo Schimmel int mlxsw_sp_port_vp_mode_set(struct mlxsw_sp_port *mlxsw_sp_port, bool enable)
44456ade8feSJiri Pirko {
44556ade8feSJiri Pirko struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
44656ade8feSJiri Pirko char svpe_pl[MLXSW_REG_SVPE_LEN];
44756ade8feSJiri Pirko
44856ade8feSJiri Pirko mlxsw_reg_svpe_pack(svpe_pl, mlxsw_sp_port->local_port, enable);
44956ade8feSJiri Pirko return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(svpe), svpe_pl);
45056ade8feSJiri Pirko }
45156ade8feSJiri Pirko
mlxsw_sp_port_vid_learning_set(struct mlxsw_sp_port * mlxsw_sp_port,u16 vid,bool learn_enable)4527cbc4277SIdo Schimmel int mlxsw_sp_port_vid_learning_set(struct mlxsw_sp_port *mlxsw_sp_port, u16 vid,
453584d73dfSIdo Schimmel bool learn_enable)
45456ade8feSJiri Pirko {
45556ade8feSJiri Pirko struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
45656ade8feSJiri Pirko char *spvmlr_pl;
45756ade8feSJiri Pirko int err;
45856ade8feSJiri Pirko
45956ade8feSJiri Pirko spvmlr_pl = kmalloc(MLXSW_REG_SPVMLR_LEN, GFP_KERNEL);
46056ade8feSJiri Pirko if (!spvmlr_pl)
46156ade8feSJiri Pirko return -ENOMEM;
4627cbc4277SIdo Schimmel mlxsw_reg_spvmlr_pack(spvmlr_pl, mlxsw_sp_port->local_port, vid, vid,
4637cbc4277SIdo Schimmel learn_enable);
46456ade8feSJiri Pirko err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(spvmlr), spvmlr_pl);
46556ade8feSJiri Pirko kfree(spvmlr_pl);
46656ade8feSJiri Pirko return err;
46756ade8feSJiri Pirko }
46856ade8feSJiri Pirko
mlxsw_sp_port_security_set(struct mlxsw_sp_port * mlxsw_sp_port,bool enable)469dc0d1a8bSIdo Schimmel int mlxsw_sp_port_security_set(struct mlxsw_sp_port *mlxsw_sp_port, bool enable)
470dc0d1a8bSIdo Schimmel {
471dc0d1a8bSIdo Schimmel struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
472dc0d1a8bSIdo Schimmel char spfsr_pl[MLXSW_REG_SPFSR_LEN];
473dc0d1a8bSIdo Schimmel int err;
474dc0d1a8bSIdo Schimmel
475dc0d1a8bSIdo Schimmel if (mlxsw_sp_port->security == enable)
476dc0d1a8bSIdo Schimmel return 0;
477dc0d1a8bSIdo Schimmel
478dc0d1a8bSIdo Schimmel mlxsw_reg_spfsr_pack(spfsr_pl, mlxsw_sp_port->local_port, enable);
479dc0d1a8bSIdo Schimmel err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(spfsr), spfsr_pl);
480dc0d1a8bSIdo Schimmel if (err)
481dc0d1a8bSIdo Schimmel return err;
482dc0d1a8bSIdo Schimmel
483dc0d1a8bSIdo Schimmel mlxsw_sp_port->security = enable;
484dc0d1a8bSIdo Schimmel return 0;
485dc0d1a8bSIdo Schimmel }
486dc0d1a8bSIdo Schimmel
mlxsw_sp_ethtype_to_sver_type(u16 ethtype,u8 * p_sver_type)4874418096eSAmit Cohen int mlxsw_sp_ethtype_to_sver_type(u16 ethtype, u8 *p_sver_type)
4883ae7a65bSAmit Cohen {
4893ae7a65bSAmit Cohen switch (ethtype) {
4903ae7a65bSAmit Cohen case ETH_P_8021Q:
4913ae7a65bSAmit Cohen *p_sver_type = 0;
4923ae7a65bSAmit Cohen break;
4933ae7a65bSAmit Cohen case ETH_P_8021AD:
4943ae7a65bSAmit Cohen *p_sver_type = 1;
4953ae7a65bSAmit Cohen break;
4963ae7a65bSAmit Cohen default:
4973ae7a65bSAmit Cohen return -EINVAL;
4983ae7a65bSAmit Cohen }
4993ae7a65bSAmit Cohen
5003ae7a65bSAmit Cohen return 0;
5013ae7a65bSAmit Cohen }
5023ae7a65bSAmit Cohen
mlxsw_sp_port_egress_ethtype_set(struct mlxsw_sp_port * mlxsw_sp_port,u16 ethtype)503114a465dSAmit Cohen int mlxsw_sp_port_egress_ethtype_set(struct mlxsw_sp_port *mlxsw_sp_port,
504114a465dSAmit Cohen u16 ethtype)
505114a465dSAmit Cohen {
506114a465dSAmit Cohen struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
507114a465dSAmit Cohen char spevet_pl[MLXSW_REG_SPEVET_LEN];
508114a465dSAmit Cohen u8 sver_type;
509114a465dSAmit Cohen int err;
510114a465dSAmit Cohen
511114a465dSAmit Cohen err = mlxsw_sp_ethtype_to_sver_type(ethtype, &sver_type);
512114a465dSAmit Cohen if (err)
513114a465dSAmit Cohen return err;
514114a465dSAmit Cohen
515114a465dSAmit Cohen mlxsw_reg_spevet_pack(spevet_pl, mlxsw_sp_port->local_port, sver_type);
516114a465dSAmit Cohen return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(spevet), spevet_pl);
517114a465dSAmit Cohen }
518114a465dSAmit Cohen
__mlxsw_sp_port_pvid_set(struct mlxsw_sp_port * mlxsw_sp_port,u16 vid,u16 ethtype)519b02eae9bSIdo Schimmel static int __mlxsw_sp_port_pvid_set(struct mlxsw_sp_port *mlxsw_sp_port,
5203ae7a65bSAmit Cohen u16 vid, u16 ethtype)
521b02eae9bSIdo Schimmel {
522b02eae9bSIdo Schimmel struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
523b02eae9bSIdo Schimmel char spvid_pl[MLXSW_REG_SPVID_LEN];
5243ae7a65bSAmit Cohen u8 sver_type;
5253ae7a65bSAmit Cohen int err;
526b02eae9bSIdo Schimmel
5273ae7a65bSAmit Cohen err = mlxsw_sp_ethtype_to_sver_type(ethtype, &sver_type);
5283ae7a65bSAmit Cohen if (err)
5293ae7a65bSAmit Cohen return err;
5303ae7a65bSAmit Cohen
5313ae7a65bSAmit Cohen mlxsw_reg_spvid_pack(spvid_pl, mlxsw_sp_port->local_port, vid,
5323ae7a65bSAmit Cohen sver_type);
5333ae7a65bSAmit Cohen
534b02eae9bSIdo Schimmel return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(spvid), spvid_pl);
535b02eae9bSIdo Schimmel }
536b02eae9bSIdo Schimmel
mlxsw_sp_port_allow_untagged_set(struct mlxsw_sp_port * mlxsw_sp_port,bool allow)537b02eae9bSIdo Schimmel static int mlxsw_sp_port_allow_untagged_set(struct mlxsw_sp_port *mlxsw_sp_port,
538b02eae9bSIdo Schimmel bool allow)
539b02eae9bSIdo Schimmel {
540b02eae9bSIdo Schimmel struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
541b02eae9bSIdo Schimmel char spaft_pl[MLXSW_REG_SPAFT_LEN];
542b02eae9bSIdo Schimmel
543b02eae9bSIdo Schimmel mlxsw_reg_spaft_pack(spaft_pl, mlxsw_sp_port->local_port, allow);
544b02eae9bSIdo Schimmel return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(spaft), spaft_pl);
545b02eae9bSIdo Schimmel }
546b02eae9bSIdo Schimmel
mlxsw_sp_port_pvid_set(struct mlxsw_sp_port * mlxsw_sp_port,u16 vid,u16 ethtype)5473ae7a65bSAmit Cohen int mlxsw_sp_port_pvid_set(struct mlxsw_sp_port *mlxsw_sp_port, u16 vid,
5483ae7a65bSAmit Cohen u16 ethtype)
549b02eae9bSIdo Schimmel {
550b02eae9bSIdo Schimmel int err;
551b02eae9bSIdo Schimmel
552b02eae9bSIdo Schimmel if (!vid) {
553b02eae9bSIdo Schimmel err = mlxsw_sp_port_allow_untagged_set(mlxsw_sp_port, false);
554b02eae9bSIdo Schimmel if (err)
555b02eae9bSIdo Schimmel return err;
556b02eae9bSIdo Schimmel } else {
5573ae7a65bSAmit Cohen err = __mlxsw_sp_port_pvid_set(mlxsw_sp_port, vid, ethtype);
558b02eae9bSIdo Schimmel if (err)
559b02eae9bSIdo Schimmel return err;
560b02eae9bSIdo Schimmel err = mlxsw_sp_port_allow_untagged_set(mlxsw_sp_port, true);
561b02eae9bSIdo Schimmel if (err)
562b02eae9bSIdo Schimmel goto err_port_allow_untagged_set;
563b02eae9bSIdo Schimmel }
564b02eae9bSIdo Schimmel
565b02eae9bSIdo Schimmel mlxsw_sp_port->pvid = vid;
566b02eae9bSIdo Schimmel return 0;
567b02eae9bSIdo Schimmel
568b02eae9bSIdo Schimmel err_port_allow_untagged_set:
5693ae7a65bSAmit Cohen __mlxsw_sp_port_pvid_set(mlxsw_sp_port, mlxsw_sp_port->pvid, ethtype);
570b02eae9bSIdo Schimmel return err;
571b02eae9bSIdo Schimmel }
572b02eae9bSIdo Schimmel
57356ade8feSJiri Pirko static int
mlxsw_sp_port_system_port_mapping_set(struct mlxsw_sp_port * mlxsw_sp_port)57456ade8feSJiri Pirko mlxsw_sp_port_system_port_mapping_set(struct mlxsw_sp_port *mlxsw_sp_port)
57556ade8feSJiri Pirko {
57656ade8feSJiri Pirko struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
57756ade8feSJiri Pirko char sspr_pl[MLXSW_REG_SSPR_LEN];
57856ade8feSJiri Pirko
57956ade8feSJiri Pirko mlxsw_reg_sspr_pack(sspr_pl, mlxsw_sp_port->local_port);
58056ade8feSJiri Pirko return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(sspr), sspr_pl);
58156ade8feSJiri Pirko }
58256ade8feSJiri Pirko
5834a7f970fSJiri Pirko static int
mlxsw_sp_port_module_info_parse(struct mlxsw_sp * mlxsw_sp,u16 local_port,char * pmlp_pl,struct mlxsw_sp_port_mapping * port_mapping)584b0ec003eSJiri Pirko mlxsw_sp_port_module_info_parse(struct mlxsw_sp *mlxsw_sp,
585b0ec003eSJiri Pirko u16 local_port, char *pmlp_pl,
5864a7f970fSJiri Pirko struct mlxsw_sp_port_mapping *port_mapping)
58756ade8feSJiri Pirko {
588c8fc10dcSJiri Pirko bool separate_rxtx;
589bac62191SJiri Pirko u8 first_lane;
5906445eef0SJiri Pirko u8 slot_index;
591c8fc10dcSJiri Pirko u8 module;
592c8fc10dcSJiri Pirko u8 width;
593c8fc10dcSJiri Pirko int i;
59456ade8feSJiri Pirko
595c8fc10dcSJiri Pirko module = mlxsw_reg_pmlp_module_get(pmlp_pl, 0);
5966445eef0SJiri Pirko slot_index = mlxsw_reg_pmlp_slot_index_get(pmlp_pl, 0);
597c8fc10dcSJiri Pirko width = mlxsw_reg_pmlp_width_get(pmlp_pl);
598c8fc10dcSJiri Pirko separate_rxtx = mlxsw_reg_pmlp_rxtx_get(pmlp_pl);
599bac62191SJiri Pirko first_lane = mlxsw_reg_pmlp_tx_lane_get(pmlp_pl, 0);
600c8fc10dcSJiri Pirko
601c8fc10dcSJiri Pirko if (width && !is_power_of_2(width)) {
602c8fc10dcSJiri Pirko dev_err(mlxsw_sp->bus_info->dev, "Port %d: Unsupported module config: width value is not power of 2\n",
603c8fc10dcSJiri Pirko local_port);
604c8fc10dcSJiri Pirko return -EINVAL;
605c8fc10dcSJiri Pirko }
606c8fc10dcSJiri Pirko
607c8fc10dcSJiri Pirko for (i = 0; i < width; i++) {
608c8fc10dcSJiri Pirko if (mlxsw_reg_pmlp_module_get(pmlp_pl, i) != module) {
609c8fc10dcSJiri Pirko dev_err(mlxsw_sp->bus_info->dev, "Port %d: Unsupported module config: contains multiple modules\n",
610c8fc10dcSJiri Pirko local_port);
611c8fc10dcSJiri Pirko return -EINVAL;
612c8fc10dcSJiri Pirko }
6136445eef0SJiri Pirko if (mlxsw_reg_pmlp_slot_index_get(pmlp_pl, i) != slot_index) {
6146445eef0SJiri Pirko dev_err(mlxsw_sp->bus_info->dev, "Port %d: Unsupported module config: contains multiple slot indexes\n",
6156445eef0SJiri Pirko local_port);
6166445eef0SJiri Pirko return -EINVAL;
6176445eef0SJiri Pirko }
618c8fc10dcSJiri Pirko if (separate_rxtx &&
619c8fc10dcSJiri Pirko mlxsw_reg_pmlp_tx_lane_get(pmlp_pl, i) !=
620c8fc10dcSJiri Pirko mlxsw_reg_pmlp_rx_lane_get(pmlp_pl, i)) {
621c8fc10dcSJiri Pirko dev_err(mlxsw_sp->bus_info->dev, "Port %d: Unsupported module config: TX and RX lane numbers are different\n",
622c8fc10dcSJiri Pirko local_port);
623c8fc10dcSJiri Pirko return -EINVAL;
624c8fc10dcSJiri Pirko }
625bac62191SJiri Pirko if (mlxsw_reg_pmlp_tx_lane_get(pmlp_pl, i) != i + first_lane) {
626c8fc10dcSJiri Pirko dev_err(mlxsw_sp->bus_info->dev, "Port %d: Unsupported module config: TX and RX lane numbers are not sequential\n",
627c8fc10dcSJiri Pirko local_port);
628c8fc10dcSJiri Pirko return -EINVAL;
629c8fc10dcSJiri Pirko }
630c8fc10dcSJiri Pirko }
631c8fc10dcSJiri Pirko
632c8fc10dcSJiri Pirko port_mapping->module = module;
6336445eef0SJiri Pirko port_mapping->slot_index = slot_index;
634c8fc10dcSJiri Pirko port_mapping->width = width;
63532ada69bSJiri Pirko port_mapping->module_width = width;
6364a7f970fSJiri Pirko port_mapping->lane = mlxsw_reg_pmlp_tx_lane_get(pmlp_pl, 0);
63756ade8feSJiri Pirko return 0;
63856ade8feSJiri Pirko }
63956ade8feSJiri Pirko
64013eb056eSJiri Pirko static int
mlxsw_sp_port_module_info_get(struct mlxsw_sp * mlxsw_sp,u16 local_port,struct mlxsw_sp_port_mapping * port_mapping)641b0ec003eSJiri Pirko mlxsw_sp_port_module_info_get(struct mlxsw_sp *mlxsw_sp, u16 local_port,
642b0ec003eSJiri Pirko struct mlxsw_sp_port_mapping *port_mapping)
643b0ec003eSJiri Pirko {
644b0ec003eSJiri Pirko char pmlp_pl[MLXSW_REG_PMLP_LEN];
645b0ec003eSJiri Pirko int err;
646b0ec003eSJiri Pirko
647b0ec003eSJiri Pirko mlxsw_reg_pmlp_pack(pmlp_pl, local_port);
648b0ec003eSJiri Pirko err = mlxsw_reg_query(mlxsw_sp->core, MLXSW_REG(pmlp), pmlp_pl);
649b0ec003eSJiri Pirko if (err)
650b0ec003eSJiri Pirko return err;
651b0ec003eSJiri Pirko return mlxsw_sp_port_module_info_parse(mlxsw_sp, local_port,
652b0ec003eSJiri Pirko pmlp_pl, port_mapping);
653b0ec003eSJiri Pirko }
654b0ec003eSJiri Pirko
655b0ec003eSJiri Pirko static int
mlxsw_sp_port_module_map(struct mlxsw_sp * mlxsw_sp,u16 local_port,const struct mlxsw_sp_port_mapping * port_mapping)656c934757dSAmit Cohen mlxsw_sp_port_module_map(struct mlxsw_sp *mlxsw_sp, u16 local_port,
65713eb056eSJiri Pirko const struct mlxsw_sp_port_mapping *port_mapping)
65818f1e70cSIdo Schimmel {
65918f1e70cSIdo Schimmel char pmlp_pl[MLXSW_REG_PMLP_LEN];
660896f399bSIdo Schimmel int i, err;
661896f399bSIdo Schimmel
6626445eef0SJiri Pirko mlxsw_env_module_port_map(mlxsw_sp->core, port_mapping->slot_index,
6636445eef0SJiri Pirko port_mapping->module);
66418f1e70cSIdo Schimmel
66513eb056eSJiri Pirko mlxsw_reg_pmlp_pack(pmlp_pl, local_port);
66635896d96SJiri Pirko mlxsw_reg_pmlp_width_set(pmlp_pl, port_mapping->width);
66735896d96SJiri Pirko for (i = 0; i < port_mapping->width; i++) {
6686445eef0SJiri Pirko mlxsw_reg_pmlp_slot_index_set(pmlp_pl, i,
6696445eef0SJiri Pirko port_mapping->slot_index);
67035896d96SJiri Pirko mlxsw_reg_pmlp_module_set(pmlp_pl, i, port_mapping->module);
67135896d96SJiri Pirko mlxsw_reg_pmlp_tx_lane_set(pmlp_pl, i, port_mapping->lane + i); /* Rx & Tx */
67218f1e70cSIdo Schimmel }
67318f1e70cSIdo Schimmel
674896f399bSIdo Schimmel err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(pmlp), pmlp_pl);
675896f399bSIdo Schimmel if (err)
676896f399bSIdo Schimmel goto err_pmlp_write;
677896f399bSIdo Schimmel return 0;
678896f399bSIdo Schimmel
679896f399bSIdo Schimmel err_pmlp_write:
6806445eef0SJiri Pirko mlxsw_env_module_port_unmap(mlxsw_sp->core, port_mapping->slot_index,
6816445eef0SJiri Pirko port_mapping->module);
682896f399bSIdo Schimmel return err;
68318f1e70cSIdo Schimmel }
68418f1e70cSIdo Schimmel
mlxsw_sp_port_module_unmap(struct mlxsw_sp * mlxsw_sp,u16 local_port,u8 slot_index,u8 module)685c934757dSAmit Cohen static void mlxsw_sp_port_module_unmap(struct mlxsw_sp *mlxsw_sp, u16 local_port,
68634945452SVadim Pasternak u8 slot_index, u8 module)
6873e9b27b8SIdo Schimmel {
6883e9b27b8SIdo Schimmel char pmlp_pl[MLXSW_REG_PMLP_LEN];
6893e9b27b8SIdo Schimmel
69013eb056eSJiri Pirko mlxsw_reg_pmlp_pack(pmlp_pl, local_port);
6913e9b27b8SIdo Schimmel mlxsw_reg_pmlp_width_set(pmlp_pl, 0);
692196bff29SIdo Schimmel mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(pmlp), pmlp_pl);
69334945452SVadim Pasternak mlxsw_env_module_port_unmap(mlxsw_sp->core, slot_index, module);
6943e9b27b8SIdo Schimmel }
6953e9b27b8SIdo Schimmel
mlxsw_sp_port_open(struct net_device * dev)69656ade8feSJiri Pirko static int mlxsw_sp_port_open(struct net_device *dev)
69756ade8feSJiri Pirko {
69856ade8feSJiri Pirko struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(dev);
699896f399bSIdo Schimmel struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
70056ade8feSJiri Pirko int err;
70156ade8feSJiri Pirko
7026445eef0SJiri Pirko err = mlxsw_env_module_port_up(mlxsw_sp->core,
7036445eef0SJiri Pirko mlxsw_sp_port->mapping.slot_index,
704896f399bSIdo Schimmel mlxsw_sp_port->mapping.module);
70556ade8feSJiri Pirko if (err)
70656ade8feSJiri Pirko return err;
707896f399bSIdo Schimmel err = mlxsw_sp_port_admin_status_set(mlxsw_sp_port, true);
708896f399bSIdo Schimmel if (err)
709896f399bSIdo Schimmel goto err_port_admin_status_set;
71056ade8feSJiri Pirko netif_start_queue(dev);
71156ade8feSJiri Pirko return 0;
712896f399bSIdo Schimmel
713896f399bSIdo Schimmel err_port_admin_status_set:
7146445eef0SJiri Pirko mlxsw_env_module_port_down(mlxsw_sp->core,
7156445eef0SJiri Pirko mlxsw_sp_port->mapping.slot_index,
716896f399bSIdo Schimmel mlxsw_sp_port->mapping.module);
717896f399bSIdo Schimmel return err;
71856ade8feSJiri Pirko }
71956ade8feSJiri Pirko
mlxsw_sp_port_stop(struct net_device * dev)72056ade8feSJiri Pirko static int mlxsw_sp_port_stop(struct net_device *dev)
72156ade8feSJiri Pirko {
72256ade8feSJiri Pirko struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(dev);
723896f399bSIdo Schimmel struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
72456ade8feSJiri Pirko
72556ade8feSJiri Pirko netif_stop_queue(dev);
72606277ca2SIdo Schimmel mlxsw_sp_port_admin_status_set(mlxsw_sp_port, false);
7276445eef0SJiri Pirko mlxsw_env_module_port_down(mlxsw_sp->core,
7286445eef0SJiri Pirko mlxsw_sp_port->mapping.slot_index,
729896f399bSIdo Schimmel mlxsw_sp_port->mapping.module);
73006277ca2SIdo Schimmel return 0;
73156ade8feSJiri Pirko }
73256ade8feSJiri Pirko
mlxsw_sp_port_xmit(struct sk_buff * skb,struct net_device * dev)73356ade8feSJiri Pirko static netdev_tx_t mlxsw_sp_port_xmit(struct sk_buff *skb,
73456ade8feSJiri Pirko struct net_device *dev)
73556ade8feSJiri Pirko {
73656ade8feSJiri Pirko struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(dev);
73756ade8feSJiri Pirko struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
73856ade8feSJiri Pirko struct mlxsw_sp_port_pcpu_stats *pcpu_stats;
73956ade8feSJiri Pirko const struct mlxsw_tx_info tx_info = {
74056ade8feSJiri Pirko .local_port = mlxsw_sp_port->local_port,
74156ade8feSJiri Pirko .is_emad = false,
74256ade8feSJiri Pirko };
74356ade8feSJiri Pirko u64 len;
74456ade8feSJiri Pirko int err;
74556ade8feSJiri Pirko
746d7cd206dSPetr Machata memset(skb->cb, 0, sizeof(struct mlxsw_skb_cb));
747d7cd206dSPetr Machata
748307c2431SJiri Pirko if (mlxsw_core_skb_transmit_busy(mlxsw_sp->core, &tx_info))
74956ade8feSJiri Pirko return NETDEV_TX_BUSY;
75056ade8feSJiri Pirko
75156ade8feSJiri Pirko if (eth_skb_pad(skb)) {
75256ade8feSJiri Pirko this_cpu_inc(mlxsw_sp_port->pcpu_stats->tx_dropped);
75356ade8feSJiri Pirko return NETDEV_TX_OK;
75456ade8feSJiri Pirko }
75556ade8feSJiri Pirko
75624157bc6SDanielle Ratson err = mlxsw_sp_txhdr_handle(mlxsw_sp->core, mlxsw_sp_port, skb,
75724157bc6SDanielle Ratson &tx_info);
75824157bc6SDanielle Ratson if (err)
75924157bc6SDanielle Ratson return NETDEV_TX_OK;
76024157bc6SDanielle Ratson
76163dcdd35SNogah Frankel /* TX header is consumed by HW on the way so we shouldn't count its
76263dcdd35SNogah Frankel * bytes as being sent.
76363dcdd35SNogah Frankel */
76463dcdd35SNogah Frankel len = skb->len - MLXSW_TXHDR_LEN;
76563dcdd35SNogah Frankel
76656ade8feSJiri Pirko /* Due to a race we might fail here because of a full queue. In that
76756ade8feSJiri Pirko * unlikely case we simply drop the packet.
76856ade8feSJiri Pirko */
769307c2431SJiri Pirko err = mlxsw_core_skb_transmit(mlxsw_sp->core, skb, &tx_info);
77056ade8feSJiri Pirko
77156ade8feSJiri Pirko if (!err) {
77256ade8feSJiri Pirko pcpu_stats = this_cpu_ptr(mlxsw_sp_port->pcpu_stats);
77356ade8feSJiri Pirko u64_stats_update_begin(&pcpu_stats->syncp);
77456ade8feSJiri Pirko pcpu_stats->tx_packets++;
77556ade8feSJiri Pirko pcpu_stats->tx_bytes += len;
77656ade8feSJiri Pirko u64_stats_update_end(&pcpu_stats->syncp);
77756ade8feSJiri Pirko } else {
77856ade8feSJiri Pirko this_cpu_inc(mlxsw_sp_port->pcpu_stats->tx_dropped);
77956ade8feSJiri Pirko dev_kfree_skb_any(skb);
78056ade8feSJiri Pirko }
78156ade8feSJiri Pirko return NETDEV_TX_OK;
78256ade8feSJiri Pirko }
78356ade8feSJiri Pirko
mlxsw_sp_set_rx_mode(struct net_device * dev)784c5b9b518SJiri Pirko static void mlxsw_sp_set_rx_mode(struct net_device *dev)
785c5b9b518SJiri Pirko {
786c5b9b518SJiri Pirko }
787c5b9b518SJiri Pirko
mlxsw_sp_port_set_mac_address(struct net_device * dev,void * p)78856ade8feSJiri Pirko static int mlxsw_sp_port_set_mac_address(struct net_device *dev, void *p)
78956ade8feSJiri Pirko {
79056ade8feSJiri Pirko struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(dev);
79156ade8feSJiri Pirko struct sockaddr *addr = p;
79256ade8feSJiri Pirko int err;
79356ade8feSJiri Pirko
79456ade8feSJiri Pirko if (!is_valid_ether_addr(addr->sa_data))
79556ade8feSJiri Pirko return -EADDRNOTAVAIL;
79656ade8feSJiri Pirko
79756ade8feSJiri Pirko err = mlxsw_sp_port_dev_addr_set(mlxsw_sp_port, addr->sa_data);
79856ade8feSJiri Pirko if (err)
79956ade8feSJiri Pirko return err;
800a05e4c0aSJakub Kicinski eth_hw_addr_set(dev, addr->sa_data);
80156ade8feSJiri Pirko return 0;
80256ade8feSJiri Pirko }
80356ade8feSJiri Pirko
mlxsw_sp_port_change_mtu(struct net_device * dev,int mtu)80456ade8feSJiri Pirko static int mlxsw_sp_port_change_mtu(struct net_device *dev, int mtu)
80556ade8feSJiri Pirko {
80656ade8feSJiri Pirko struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(dev);
8070103a3e4SPetr Machata struct mlxsw_sp_hdroom orig_hdroom;
8080103a3e4SPetr Machata struct mlxsw_sp_hdroom hdroom;
80956ade8feSJiri Pirko int err;
81056ade8feSJiri Pirko
8110103a3e4SPetr Machata orig_hdroom = *mlxsw_sp_port->hdroom;
8120103a3e4SPetr Machata
8130103a3e4SPetr Machata hdroom = orig_hdroom;
8140103a3e4SPetr Machata hdroom.mtu = mtu;
8152d9f703fSPetr Machata mlxsw_sp_hdroom_bufs_reset_sizes(mlxsw_sp_port, &hdroom);
8162d9f703fSPetr Machata
8172d9f703fSPetr Machata err = mlxsw_sp_hdroom_configure(mlxsw_sp_port, &hdroom);
8182d9f703fSPetr Machata if (err) {
8192d9f703fSPetr Machata netdev_err(dev, "Failed to configure port's headroom\n");
82056ade8feSJiri Pirko return err;
8212d9f703fSPetr Machata }
8220103a3e4SPetr Machata
823ff6551ecSIdo Schimmel err = mlxsw_sp_port_mtu_set(mlxsw_sp_port, mtu);
824ff6551ecSIdo Schimmel if (err)
825ff6551ecSIdo Schimmel goto err_port_mtu_set;
82656ade8feSJiri Pirko dev->mtu = mtu;
82756ade8feSJiri Pirko return 0;
828ff6551ecSIdo Schimmel
829ff6551ecSIdo Schimmel err_port_mtu_set:
8302d9f703fSPetr Machata mlxsw_sp_hdroom_configure(mlxsw_sp_port, &orig_hdroom);
831ff6551ecSIdo Schimmel return err;
83256ade8feSJiri Pirko }
83356ade8feSJiri Pirko
8344bdcc6caSOr Gerlitz static int
mlxsw_sp_port_get_sw_stats64(const struct net_device * dev,struct rtnl_link_stats64 * stats)835fc1bbb0fSNogah Frankel mlxsw_sp_port_get_sw_stats64(const struct net_device *dev,
83656ade8feSJiri Pirko struct rtnl_link_stats64 *stats)
83756ade8feSJiri Pirko {
83856ade8feSJiri Pirko struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(dev);
83956ade8feSJiri Pirko struct mlxsw_sp_port_pcpu_stats *p;
84056ade8feSJiri Pirko u64 rx_packets, rx_bytes, tx_packets, tx_bytes;
84156ade8feSJiri Pirko u32 tx_dropped = 0;
84256ade8feSJiri Pirko unsigned int start;
84356ade8feSJiri Pirko int i;
84456ade8feSJiri Pirko
84556ade8feSJiri Pirko for_each_possible_cpu(i) {
84656ade8feSJiri Pirko p = per_cpu_ptr(mlxsw_sp_port->pcpu_stats, i);
84756ade8feSJiri Pirko do {
848068c38adSThomas Gleixner start = u64_stats_fetch_begin(&p->syncp);
84956ade8feSJiri Pirko rx_packets = p->rx_packets;
85056ade8feSJiri Pirko rx_bytes = p->rx_bytes;
85156ade8feSJiri Pirko tx_packets = p->tx_packets;
85256ade8feSJiri Pirko tx_bytes = p->tx_bytes;
853068c38adSThomas Gleixner } while (u64_stats_fetch_retry(&p->syncp, start));
85456ade8feSJiri Pirko
85556ade8feSJiri Pirko stats->rx_packets += rx_packets;
85656ade8feSJiri Pirko stats->rx_bytes += rx_bytes;
85756ade8feSJiri Pirko stats->tx_packets += tx_packets;
85856ade8feSJiri Pirko stats->tx_bytes += tx_bytes;
85956ade8feSJiri Pirko /* tx_dropped is u32, updated without syncp protection. */
86056ade8feSJiri Pirko tx_dropped += p->tx_dropped;
86156ade8feSJiri Pirko }
86256ade8feSJiri Pirko stats->tx_dropped = tx_dropped;
863fc1bbb0fSNogah Frankel return 0;
864fc1bbb0fSNogah Frankel }
865fc1bbb0fSNogah Frankel
mlxsw_sp_port_has_offload_stats(const struct net_device * dev,int attr_id)8663df5b3c6SOr Gerlitz static bool mlxsw_sp_port_has_offload_stats(const struct net_device *dev, int attr_id)
867fc1bbb0fSNogah Frankel {
868fc1bbb0fSNogah Frankel switch (attr_id) {
869fc1bbb0fSNogah Frankel case IFLA_OFFLOAD_XSTATS_CPU_HIT:
870fc1bbb0fSNogah Frankel return true;
871fc1bbb0fSNogah Frankel }
872fc1bbb0fSNogah Frankel
873fc1bbb0fSNogah Frankel return false;
874fc1bbb0fSNogah Frankel }
875fc1bbb0fSNogah Frankel
mlxsw_sp_port_get_offload_stats(int attr_id,const struct net_device * dev,void * sp)8764bdcc6caSOr Gerlitz static int mlxsw_sp_port_get_offload_stats(int attr_id, const struct net_device *dev,
877fc1bbb0fSNogah Frankel void *sp)
878fc1bbb0fSNogah Frankel {
879fc1bbb0fSNogah Frankel switch (attr_id) {
880fc1bbb0fSNogah Frankel case IFLA_OFFLOAD_XSTATS_CPU_HIT:
881fc1bbb0fSNogah Frankel return mlxsw_sp_port_get_sw_stats64(dev, sp);
882fc1bbb0fSNogah Frankel }
883fc1bbb0fSNogah Frankel
884fc1bbb0fSNogah Frankel return -EINVAL;
885fc1bbb0fSNogah Frankel }
886fc1bbb0fSNogah Frankel
mlxsw_sp_port_get_stats_raw(struct net_device * dev,int grp,int prio,char * ppcnt_pl)887614d509aSAmit Cohen int mlxsw_sp_port_get_stats_raw(struct net_device *dev, int grp,
888fc1bbb0fSNogah Frankel int prio, char *ppcnt_pl)
889fc1bbb0fSNogah Frankel {
890fc1bbb0fSNogah Frankel struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(dev);
891fc1bbb0fSNogah Frankel struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
892fc1bbb0fSNogah Frankel
893fc1bbb0fSNogah Frankel mlxsw_reg_ppcnt_pack(ppcnt_pl, mlxsw_sp_port->local_port, grp, prio);
894fc1bbb0fSNogah Frankel return mlxsw_reg_query(mlxsw_sp->core, MLXSW_REG(ppcnt), ppcnt_pl);
895fc1bbb0fSNogah Frankel }
896fc1bbb0fSNogah Frankel
mlxsw_sp_port_get_hw_stats(struct net_device * dev,struct rtnl_link_stats64 * stats)897fc1bbb0fSNogah Frankel static int mlxsw_sp_port_get_hw_stats(struct net_device *dev,
898fc1bbb0fSNogah Frankel struct rtnl_link_stats64 *stats)
899fc1bbb0fSNogah Frankel {
900fc1bbb0fSNogah Frankel char ppcnt_pl[MLXSW_REG_PPCNT_LEN];
901fc1bbb0fSNogah Frankel int err;
902fc1bbb0fSNogah Frankel
903fc1bbb0fSNogah Frankel err = mlxsw_sp_port_get_stats_raw(dev, MLXSW_REG_PPCNT_IEEE_8023_CNT,
904fc1bbb0fSNogah Frankel 0, ppcnt_pl);
905fc1bbb0fSNogah Frankel if (err)
906fc1bbb0fSNogah Frankel goto out;
907fc1bbb0fSNogah Frankel
908fc1bbb0fSNogah Frankel stats->tx_packets =
909fc1bbb0fSNogah Frankel mlxsw_reg_ppcnt_a_frames_transmitted_ok_get(ppcnt_pl);
910fc1bbb0fSNogah Frankel stats->rx_packets =
911fc1bbb0fSNogah Frankel mlxsw_reg_ppcnt_a_frames_received_ok_get(ppcnt_pl);
912fc1bbb0fSNogah Frankel stats->tx_bytes =
913fc1bbb0fSNogah Frankel mlxsw_reg_ppcnt_a_octets_transmitted_ok_get(ppcnt_pl);
914fc1bbb0fSNogah Frankel stats->rx_bytes =
915fc1bbb0fSNogah Frankel mlxsw_reg_ppcnt_a_octets_received_ok_get(ppcnt_pl);
916fc1bbb0fSNogah Frankel stats->multicast =
917fc1bbb0fSNogah Frankel mlxsw_reg_ppcnt_a_multicast_frames_received_ok_get(ppcnt_pl);
918fc1bbb0fSNogah Frankel
919fc1bbb0fSNogah Frankel stats->rx_crc_errors =
920fc1bbb0fSNogah Frankel mlxsw_reg_ppcnt_a_frame_check_sequence_errors_get(ppcnt_pl);
921fc1bbb0fSNogah Frankel stats->rx_frame_errors =
922fc1bbb0fSNogah Frankel mlxsw_reg_ppcnt_a_alignment_errors_get(ppcnt_pl);
923fc1bbb0fSNogah Frankel
924fc1bbb0fSNogah Frankel stats->rx_length_errors = (
925fc1bbb0fSNogah Frankel mlxsw_reg_ppcnt_a_in_range_length_errors_get(ppcnt_pl) +
926fc1bbb0fSNogah Frankel mlxsw_reg_ppcnt_a_out_of_range_length_field_get(ppcnt_pl) +
927fc1bbb0fSNogah Frankel mlxsw_reg_ppcnt_a_frame_too_long_errors_get(ppcnt_pl));
928fc1bbb0fSNogah Frankel
929fc1bbb0fSNogah Frankel stats->rx_errors = (stats->rx_crc_errors +
930fc1bbb0fSNogah Frankel stats->rx_frame_errors + stats->rx_length_errors);
931fc1bbb0fSNogah Frankel
932fc1bbb0fSNogah Frankel out:
933fc1bbb0fSNogah Frankel return err;
934fc1bbb0fSNogah Frankel }
935fc1bbb0fSNogah Frankel
936075ab8adSNogah Frankel static void
mlxsw_sp_port_get_hw_xstats(struct net_device * dev,struct mlxsw_sp_port_xstats * xstats)937075ab8adSNogah Frankel mlxsw_sp_port_get_hw_xstats(struct net_device *dev,
938075ab8adSNogah Frankel struct mlxsw_sp_port_xstats *xstats)
939075ab8adSNogah Frankel {
940075ab8adSNogah Frankel char ppcnt_pl[MLXSW_REG_PPCNT_LEN];
941075ab8adSNogah Frankel int err, i;
942075ab8adSNogah Frankel
943075ab8adSNogah Frankel err = mlxsw_sp_port_get_stats_raw(dev, MLXSW_REG_PPCNT_EXT_CNT, 0,
944075ab8adSNogah Frankel ppcnt_pl);
945075ab8adSNogah Frankel if (!err)
946075ab8adSNogah Frankel xstats->ecn = mlxsw_reg_ppcnt_ecn_marked_get(ppcnt_pl);
947075ab8adSNogah Frankel
948075ab8adSNogah Frankel for (i = 0; i < TC_MAX_QUEUE; i++) {
949075ab8adSNogah Frankel err = mlxsw_sp_port_get_stats_raw(dev,
950fc372cc0SPetr Machata MLXSW_REG_PPCNT_TC_CONG_CNT,
951075ab8adSNogah Frankel i, ppcnt_pl);
95215be36b8SPetr Machata if (err)
95315be36b8SPetr Machata goto tc_cnt;
95415be36b8SPetr Machata
955075ab8adSNogah Frankel xstats->wred_drop[i] =
956075ab8adSNogah Frankel mlxsw_reg_ppcnt_wred_discard_get(ppcnt_pl);
95715be36b8SPetr Machata xstats->tc_ecn[i] = mlxsw_reg_ppcnt_ecn_marked_tc_get(ppcnt_pl);
958075ab8adSNogah Frankel
95915be36b8SPetr Machata tc_cnt:
960075ab8adSNogah Frankel err = mlxsw_sp_port_get_stats_raw(dev, MLXSW_REG_PPCNT_TC_CNT,
961075ab8adSNogah Frankel i, ppcnt_pl);
962075ab8adSNogah Frankel if (err)
963075ab8adSNogah Frankel continue;
964075ab8adSNogah Frankel
965075ab8adSNogah Frankel xstats->backlog[i] =
966075ab8adSNogah Frankel mlxsw_reg_ppcnt_tc_transmit_queue_get(ppcnt_pl);
967075ab8adSNogah Frankel xstats->tail_drop[i] =
968075ab8adSNogah Frankel mlxsw_reg_ppcnt_tc_no_buffer_discard_uc_get(ppcnt_pl);
969075ab8adSNogah Frankel }
9702f88047eSNogah Frankel
9712f88047eSNogah Frankel for (i = 0; i < IEEE_8021QAZ_MAX_TCS; i++) {
9722f88047eSNogah Frankel err = mlxsw_sp_port_get_stats_raw(dev, MLXSW_REG_PPCNT_PRIO_CNT,
9732f88047eSNogah Frankel i, ppcnt_pl);
9742f88047eSNogah Frankel if (err)
9752f88047eSNogah Frankel continue;
9762f88047eSNogah Frankel
9772f88047eSNogah Frankel xstats->tx_packets[i] = mlxsw_reg_ppcnt_tx_frames_get(ppcnt_pl);
9782f88047eSNogah Frankel xstats->tx_bytes[i] = mlxsw_reg_ppcnt_tx_octets_get(ppcnt_pl);
9792f88047eSNogah Frankel }
980075ab8adSNogah Frankel }
981075ab8adSNogah Frankel
update_stats_cache(struct work_struct * work)982fc1bbb0fSNogah Frankel static void update_stats_cache(struct work_struct *work)
983fc1bbb0fSNogah Frankel {
984fc1bbb0fSNogah Frankel struct mlxsw_sp_port *mlxsw_sp_port =
985fc1bbb0fSNogah Frankel container_of(work, struct mlxsw_sp_port,
9869deef43dSNogah Frankel periodic_hw_stats.update_dw.work);
987fc1bbb0fSNogah Frankel
988fc1bbb0fSNogah Frankel if (!netif_carrier_ok(mlxsw_sp_port->dev))
989ca7609ffSPetr Machata /* Note: mlxsw_sp_port_down_wipe_counters() clears the cache as
990ca7609ffSPetr Machata * necessary when port goes down.
991ca7609ffSPetr Machata */
992fc1bbb0fSNogah Frankel goto out;
993fc1bbb0fSNogah Frankel
994fc1bbb0fSNogah Frankel mlxsw_sp_port_get_hw_stats(mlxsw_sp_port->dev,
9959deef43dSNogah Frankel &mlxsw_sp_port->periodic_hw_stats.stats);
996075ab8adSNogah Frankel mlxsw_sp_port_get_hw_xstats(mlxsw_sp_port->dev,
997075ab8adSNogah Frankel &mlxsw_sp_port->periodic_hw_stats.xstats);
998fc1bbb0fSNogah Frankel
999fc1bbb0fSNogah Frankel out:
10009deef43dSNogah Frankel mlxsw_core_schedule_dw(&mlxsw_sp_port->periodic_hw_stats.update_dw,
1001fc1bbb0fSNogah Frankel MLXSW_HW_STATS_UPDATE_TIME);
1002fc1bbb0fSNogah Frankel }
1003fc1bbb0fSNogah Frankel
1004fc1bbb0fSNogah Frankel /* Return the stats from a cache that is updated periodically,
1005fc1bbb0fSNogah Frankel * as this function might get called in an atomic context.
1006fc1bbb0fSNogah Frankel */
1007bc1f4470Sstephen hemminger static void
mlxsw_sp_port_get_stats64(struct net_device * dev,struct rtnl_link_stats64 * stats)1008fc1bbb0fSNogah Frankel mlxsw_sp_port_get_stats64(struct net_device *dev,
1009fc1bbb0fSNogah Frankel struct rtnl_link_stats64 *stats)
1010fc1bbb0fSNogah Frankel {
1011fc1bbb0fSNogah Frankel struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(dev);
1012fc1bbb0fSNogah Frankel
10139deef43dSNogah Frankel memcpy(stats, &mlxsw_sp_port->periodic_hw_stats.stats, sizeof(*stats));
101456ade8feSJiri Pirko }
101556ade8feSJiri Pirko
__mlxsw_sp_port_vlan_set(struct mlxsw_sp_port * mlxsw_sp_port,u16 vid_begin,u16 vid_end,bool is_member,bool untagged)101693cd0813SJiri Pirko static int __mlxsw_sp_port_vlan_set(struct mlxsw_sp_port *mlxsw_sp_port,
101793cd0813SJiri Pirko u16 vid_begin, u16 vid_end,
101893cd0813SJiri Pirko bool is_member, bool untagged)
101956ade8feSJiri Pirko {
102056ade8feSJiri Pirko struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
102156ade8feSJiri Pirko char *spvm_pl;
102256ade8feSJiri Pirko int err;
102356ade8feSJiri Pirko
102456ade8feSJiri Pirko spvm_pl = kmalloc(MLXSW_REG_SPVM_LEN, GFP_KERNEL);
102556ade8feSJiri Pirko if (!spvm_pl)
102656ade8feSJiri Pirko return -ENOMEM;
102756ade8feSJiri Pirko
102856ade8feSJiri Pirko mlxsw_reg_spvm_pack(spvm_pl, mlxsw_sp_port->local_port, vid_begin,
102956ade8feSJiri Pirko vid_end, is_member, untagged);
103056ade8feSJiri Pirko err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(spvm), spvm_pl);
103156ade8feSJiri Pirko kfree(spvm_pl);
103256ade8feSJiri Pirko return err;
103356ade8feSJiri Pirko }
103456ade8feSJiri Pirko
mlxsw_sp_port_vlan_set(struct mlxsw_sp_port * mlxsw_sp_port,u16 vid_begin,u16 vid_end,bool is_member,bool untagged)103593cd0813SJiri Pirko int mlxsw_sp_port_vlan_set(struct mlxsw_sp_port *mlxsw_sp_port, u16 vid_begin,
103693cd0813SJiri Pirko u16 vid_end, bool is_member, bool untagged)
103793cd0813SJiri Pirko {
103893cd0813SJiri Pirko u16 vid, vid_e;
103993cd0813SJiri Pirko int err;
104093cd0813SJiri Pirko
104193cd0813SJiri Pirko for (vid = vid_begin; vid <= vid_end;
104293cd0813SJiri Pirko vid += MLXSW_REG_SPVM_REC_MAX_COUNT) {
104393cd0813SJiri Pirko vid_e = min((u16) (vid + MLXSW_REG_SPVM_REC_MAX_COUNT - 1),
104493cd0813SJiri Pirko vid_end);
104593cd0813SJiri Pirko
104693cd0813SJiri Pirko err = __mlxsw_sp_port_vlan_set(mlxsw_sp_port, vid, vid_e,
104793cd0813SJiri Pirko is_member, untagged);
104893cd0813SJiri Pirko if (err)
104993cd0813SJiri Pirko return err;
105093cd0813SJiri Pirko }
105193cd0813SJiri Pirko
105293cd0813SJiri Pirko return 0;
105393cd0813SJiri Pirko }
105493cd0813SJiri Pirko
mlxsw_sp_port_vlan_flush(struct mlxsw_sp_port * mlxsw_sp_port,bool flush_default)1055ab6c3b79SIdo Schimmel static void mlxsw_sp_port_vlan_flush(struct mlxsw_sp_port *mlxsw_sp_port,
1056ab6c3b79SIdo Schimmel bool flush_default)
10577f71eb46SIdo Schimmel {
1058c57529e1SIdo Schimmel struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan, *tmp;
10597f71eb46SIdo Schimmel
1060c57529e1SIdo Schimmel list_for_each_entry_safe(mlxsw_sp_port_vlan, tmp,
1061ab6c3b79SIdo Schimmel &mlxsw_sp_port->vlans_list, list) {
1062ab6c3b79SIdo Schimmel if (!flush_default &&
1063ab6c3b79SIdo Schimmel mlxsw_sp_port_vlan->vid == MLXSW_SP_DEFAULT_VID)
1064ab6c3b79SIdo Schimmel continue;
1065635c8c8bSIdo Schimmel mlxsw_sp_port_vlan_destroy(mlxsw_sp_port_vlan);
10667f71eb46SIdo Schimmel }
1067ab6c3b79SIdo Schimmel }
10687f71eb46SIdo Schimmel
106916f6acebSIdo Schimmel static void
mlxsw_sp_port_vlan_cleanup(struct mlxsw_sp_port_vlan * mlxsw_sp_port_vlan)107016f6acebSIdo Schimmel mlxsw_sp_port_vlan_cleanup(struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan)
107116f6acebSIdo Schimmel {
107216f6acebSIdo Schimmel if (mlxsw_sp_port_vlan->bridge_port)
107316f6acebSIdo Schimmel mlxsw_sp_port_vlan_bridge_leave(mlxsw_sp_port_vlan);
107416f6acebSIdo Schimmel else if (mlxsw_sp_port_vlan->fid)
107516f6acebSIdo Schimmel mlxsw_sp_port_vlan_router_leave(mlxsw_sp_port_vlan);
107616f6acebSIdo Schimmel }
107716f6acebSIdo Schimmel
1078635c8c8bSIdo Schimmel struct mlxsw_sp_port_vlan *
mlxsw_sp_port_vlan_create(struct mlxsw_sp_port * mlxsw_sp_port,u16 vid)107931a08a52SIdo Schimmel mlxsw_sp_port_vlan_create(struct mlxsw_sp_port *mlxsw_sp_port, u16 vid)
108031a08a52SIdo Schimmel {
108131a08a52SIdo Schimmel struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan;
1082a2d2a205SIdo Schimmel bool untagged = vid == MLXSW_SP_DEFAULT_VID;
1083c57529e1SIdo Schimmel int err;
1084c57529e1SIdo Schimmel
1085635c8c8bSIdo Schimmel mlxsw_sp_port_vlan = mlxsw_sp_port_vlan_find_by_vid(mlxsw_sp_port, vid);
1086635c8c8bSIdo Schimmel if (mlxsw_sp_port_vlan)
1087635c8c8bSIdo Schimmel return ERR_PTR(-EEXIST);
1088635c8c8bSIdo Schimmel
1089c57529e1SIdo Schimmel err = mlxsw_sp_port_vlan_set(mlxsw_sp_port, vid, vid, true, untagged);
1090c57529e1SIdo Schimmel if (err)
1091c57529e1SIdo Schimmel return ERR_PTR(err);
109231a08a52SIdo Schimmel
109331a08a52SIdo Schimmel mlxsw_sp_port_vlan = kzalloc(sizeof(*mlxsw_sp_port_vlan), GFP_KERNEL);
1094c57529e1SIdo Schimmel if (!mlxsw_sp_port_vlan) {
1095c57529e1SIdo Schimmel err = -ENOMEM;
1096c57529e1SIdo Schimmel goto err_port_vlan_alloc;
1097c57529e1SIdo Schimmel }
109831a08a52SIdo Schimmel
109931a08a52SIdo Schimmel mlxsw_sp_port_vlan->mlxsw_sp_port = mlxsw_sp_port;
110031a08a52SIdo Schimmel mlxsw_sp_port_vlan->vid = vid;
110131a08a52SIdo Schimmel list_add(&mlxsw_sp_port_vlan->list, &mlxsw_sp_port->vlans_list);
110231a08a52SIdo Schimmel
110331a08a52SIdo Schimmel return mlxsw_sp_port_vlan;
1104c57529e1SIdo Schimmel
1105c57529e1SIdo Schimmel err_port_vlan_alloc:
1106c57529e1SIdo Schimmel mlxsw_sp_port_vlan_set(mlxsw_sp_port, vid, vid, false, false);
1107c57529e1SIdo Schimmel return ERR_PTR(err);
110831a08a52SIdo Schimmel }
110931a08a52SIdo Schimmel
mlxsw_sp_port_vlan_destroy(struct mlxsw_sp_port_vlan * mlxsw_sp_port_vlan)1110635c8c8bSIdo Schimmel void mlxsw_sp_port_vlan_destroy(struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan)
111131a08a52SIdo Schimmel {
1112c57529e1SIdo Schimmel struct mlxsw_sp_port *mlxsw_sp_port = mlxsw_sp_port_vlan->mlxsw_sp_port;
1113c57529e1SIdo Schimmel u16 vid = mlxsw_sp_port_vlan->vid;
11147cbecf24SIdo Schimmel
111516f6acebSIdo Schimmel mlxsw_sp_port_vlan_cleanup(mlxsw_sp_port_vlan);
111631a08a52SIdo Schimmel list_del(&mlxsw_sp_port_vlan->list);
111731a08a52SIdo Schimmel kfree(mlxsw_sp_port_vlan);
1118c57529e1SIdo Schimmel mlxsw_sp_port_vlan_set(mlxsw_sp_port, vid, vid, false, false);
1119c57529e1SIdo Schimmel }
1120c57529e1SIdo Schimmel
mlxsw_sp_port_add_vid(struct net_device * dev,__be16 __always_unused proto,u16 vid)112105978481SIdo Schimmel static int mlxsw_sp_port_add_vid(struct net_device *dev,
112205978481SIdo Schimmel __be16 __always_unused proto, u16 vid)
112356ade8feSJiri Pirko {
112456ade8feSJiri Pirko struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(dev);
112556ade8feSJiri Pirko
112656ade8feSJiri Pirko /* VLAN 0 is added to HW filter when device goes up, but it is
112756ade8feSJiri Pirko * reserved in our case, so simply return.
112856ade8feSJiri Pirko */
112956ade8feSJiri Pirko if (!vid)
113056ade8feSJiri Pirko return 0;
113156ade8feSJiri Pirko
1132635c8c8bSIdo Schimmel return PTR_ERR_OR_ZERO(mlxsw_sp_port_vlan_create(mlxsw_sp_port, vid));
113356ade8feSJiri Pirko }
113456ade8feSJiri Pirko
mlxsw_sp_port_kill_vid(struct net_device * dev,__be16 __always_unused proto,u16 vid)1135ec4643caSPetr Machata int mlxsw_sp_port_kill_vid(struct net_device *dev,
113656ade8feSJiri Pirko __be16 __always_unused proto, u16 vid)
113756ade8feSJiri Pirko {
113856ade8feSJiri Pirko struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(dev);
113931a08a52SIdo Schimmel struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan;
114056ade8feSJiri Pirko
114156ade8feSJiri Pirko /* VLAN 0 is removed from HW filter when device goes down, but
114256ade8feSJiri Pirko * it is reserved in our case, so simply return.
114356ade8feSJiri Pirko */
114456ade8feSJiri Pirko if (!vid)
114556ade8feSJiri Pirko return 0;
114656ade8feSJiri Pirko
114731a08a52SIdo Schimmel mlxsw_sp_port_vlan = mlxsw_sp_port_vlan_find_by_vid(mlxsw_sp_port, vid);
1148c57529e1SIdo Schimmel if (!mlxsw_sp_port_vlan)
114931a08a52SIdo Schimmel return 0;
1150635c8c8bSIdo Schimmel mlxsw_sp_port_vlan_destroy(mlxsw_sp_port_vlan);
115131a08a52SIdo Schimmel
115256ade8feSJiri Pirko return 0;
115356ade8feSJiri Pirko }
115456ade8feSJiri Pirko
mlxsw_sp_setup_tc_block(struct mlxsw_sp_port * mlxsw_sp_port,struct flow_block_offload * f)1155f7a439cbSPetr Machata static int mlxsw_sp_setup_tc_block(struct mlxsw_sp_port *mlxsw_sp_port,
1156f7a439cbSPetr Machata struct flow_block_offload *f)
1157f7a439cbSPetr Machata {
1158f7a439cbSPetr Machata switch (f->binder_type) {
1159f7a439cbSPetr Machata case FLOW_BLOCK_BINDER_TYPE_CLSACT_INGRESS:
1160f7a439cbSPetr Machata return mlxsw_sp_setup_tc_block_clsact(mlxsw_sp_port, f, true);
1161f7a439cbSPetr Machata case FLOW_BLOCK_BINDER_TYPE_CLSACT_EGRESS:
1162f7a439cbSPetr Machata return mlxsw_sp_setup_tc_block_clsact(mlxsw_sp_port, f, false);
1163f6668eacSPetr Machata case FLOW_BLOCK_BINDER_TYPE_RED_EARLY_DROP:
1164f6668eacSPetr Machata return mlxsw_sp_setup_tc_block_qevent_early_drop(mlxsw_sp_port, f);
11659c18eaf2SPetr Machata case FLOW_BLOCK_BINDER_TYPE_RED_MARK:
11669c18eaf2SPetr Machata return mlxsw_sp_setup_tc_block_qevent_mark(mlxsw_sp_port, f);
1167f7a439cbSPetr Machata default:
1168f7a439cbSPetr Machata return -EOPNOTSUPP;
1169f7a439cbSPetr Machata }
1170f7a439cbSPetr Machata }
1171f7a439cbSPetr Machata
mlxsw_sp_setup_tc(struct net_device * dev,enum tc_setup_type type,void * type_data)1172fd33f1dfSJiri Pirko static int mlxsw_sp_setup_tc(struct net_device *dev, enum tc_setup_type type,
1173de4784caSJiri Pirko void *type_data)
1174fd33f1dfSJiri Pirko {
1175fd33f1dfSJiri Pirko struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(dev);
1176fd33f1dfSJiri Pirko
1177fd33f1dfSJiri Pirko switch (type) {
1178eb49cfaaSJiri Pirko case TC_SETUP_BLOCK:
1179eb49cfaaSJiri Pirko return mlxsw_sp_setup_tc_block(mlxsw_sp_port, type_data);
118096f17e07SNogah Frankel case TC_SETUP_QDISC_RED:
118196f17e07SNogah Frankel return mlxsw_sp_setup_tc_red(mlxsw_sp_port, type_data);
118246a3615bSNogah Frankel case TC_SETUP_QDISC_PRIO:
118346a3615bSNogah Frankel return mlxsw_sp_setup_tc_prio(mlxsw_sp_port, type_data);
118419f405b9SPetr Machata case TC_SETUP_QDISC_ETS:
118519f405b9SPetr Machata return mlxsw_sp_setup_tc_ets(mlxsw_sp_port, type_data);
1186a44f58c4SPetr Machata case TC_SETUP_QDISC_TBF:
1187a44f58c4SPetr Machata return mlxsw_sp_setup_tc_tbf(mlxsw_sp_port, type_data);
11887bec1a45SPetr Machata case TC_SETUP_QDISC_FIFO:
11897bec1a45SPetr Machata return mlxsw_sp_setup_tc_fifo(mlxsw_sp_port, type_data);
11902572ac53SJiri Pirko default:
1191e915ac68SYotam Gigi return -EOPNOTSUPP;
1192763b4b70SYotam Gigi }
11932572ac53SJiri Pirko }
1194763b4b70SYotam Gigi
mlxsw_sp_feature_hw_tc(struct net_device * dev,bool enable)11959454d930SJiri Pirko static int mlxsw_sp_feature_hw_tc(struct net_device *dev, bool enable)
11969454d930SJiri Pirko {
11979454d930SJiri Pirko struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(dev);
11989454d930SJiri Pirko
11993aaff323SJiri Pirko if (!enable) {
12003bc3ffb6SJiri Pirko if (mlxsw_sp_flow_block_rule_count(mlxsw_sp_port->ing_flow_block) ||
12013c650136SJiri Pirko mlxsw_sp_flow_block_rule_count(mlxsw_sp_port->eg_flow_block)) {
12029454d930SJiri Pirko netdev_err(dev, "Active offloaded tc filters, can't turn hw_tc_offload off\n");
12039454d930SJiri Pirko return -EINVAL;
12049454d930SJiri Pirko }
12053bc3ffb6SJiri Pirko mlxsw_sp_flow_block_disable_inc(mlxsw_sp_port->ing_flow_block);
12063bc3ffb6SJiri Pirko mlxsw_sp_flow_block_disable_inc(mlxsw_sp_port->eg_flow_block);
12073aaff323SJiri Pirko } else {
12083bc3ffb6SJiri Pirko mlxsw_sp_flow_block_disable_dec(mlxsw_sp_port->ing_flow_block);
12093bc3ffb6SJiri Pirko mlxsw_sp_flow_block_disable_dec(mlxsw_sp_port->eg_flow_block);
12103aaff323SJiri Pirko }
12119454d930SJiri Pirko return 0;
12129454d930SJiri Pirko }
12139454d930SJiri Pirko
mlxsw_sp_feature_loopback(struct net_device * dev,bool enable)12148e44c0ceSJiri Pirko static int mlxsw_sp_feature_loopback(struct net_device *dev, bool enable)
12158e44c0ceSJiri Pirko {
12168e44c0ceSJiri Pirko struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(dev);
12178e44c0ceSJiri Pirko char pplr_pl[MLXSW_REG_PPLR_LEN];
12188e44c0ceSJiri Pirko int err;
12198e44c0ceSJiri Pirko
12208e44c0ceSJiri Pirko if (netif_running(dev))
12218e44c0ceSJiri Pirko mlxsw_sp_port_admin_status_set(mlxsw_sp_port, false);
12228e44c0ceSJiri Pirko
12238e44c0ceSJiri Pirko mlxsw_reg_pplr_pack(pplr_pl, mlxsw_sp_port->local_port, enable);
12248e44c0ceSJiri Pirko err = mlxsw_reg_write(mlxsw_sp_port->mlxsw_sp->core, MLXSW_REG(pplr),
12258e44c0ceSJiri Pirko pplr_pl);
12268e44c0ceSJiri Pirko
12278e44c0ceSJiri Pirko if (netif_running(dev))
12288e44c0ceSJiri Pirko mlxsw_sp_port_admin_status_set(mlxsw_sp_port, true);
12298e44c0ceSJiri Pirko
12308e44c0ceSJiri Pirko return err;
12318e44c0ceSJiri Pirko }
12328e44c0ceSJiri Pirko
12339454d930SJiri Pirko typedef int (*mlxsw_sp_feature_handler)(struct net_device *dev, bool enable);
12349454d930SJiri Pirko
mlxsw_sp_handle_feature(struct net_device * dev,netdev_features_t wanted_features,netdev_features_t feature,mlxsw_sp_feature_handler feature_handler)12359454d930SJiri Pirko static int mlxsw_sp_handle_feature(struct net_device *dev,
12369454d930SJiri Pirko netdev_features_t wanted_features,
12379454d930SJiri Pirko netdev_features_t feature,
12389454d930SJiri Pirko mlxsw_sp_feature_handler feature_handler)
12399454d930SJiri Pirko {
12409454d930SJiri Pirko netdev_features_t changes = wanted_features ^ dev->features;
12419454d930SJiri Pirko bool enable = !!(wanted_features & feature);
12429454d930SJiri Pirko int err;
12439454d930SJiri Pirko
12449454d930SJiri Pirko if (!(changes & feature))
12459454d930SJiri Pirko return 0;
12469454d930SJiri Pirko
12479454d930SJiri Pirko err = feature_handler(dev, enable);
12489454d930SJiri Pirko if (err) {
12499454d930SJiri Pirko netdev_err(dev, "%s feature %pNF failed, err %d\n",
12509454d930SJiri Pirko enable ? "Enable" : "Disable", &feature, err);
12519454d930SJiri Pirko return err;
12529454d930SJiri Pirko }
12539454d930SJiri Pirko
12549454d930SJiri Pirko if (enable)
12559454d930SJiri Pirko dev->features |= feature;
12569454d930SJiri Pirko else
12579454d930SJiri Pirko dev->features &= ~feature;
12589454d930SJiri Pirko
12599454d930SJiri Pirko return 0;
12609454d930SJiri Pirko }
mlxsw_sp_set_features(struct net_device * dev,netdev_features_t features)12619454d930SJiri Pirko static int mlxsw_sp_set_features(struct net_device *dev,
12629454d930SJiri Pirko netdev_features_t features)
12639454d930SJiri Pirko {
12648e44c0ceSJiri Pirko netdev_features_t oper_features = dev->features;
12658e44c0ceSJiri Pirko int err = 0;
12668e44c0ceSJiri Pirko
12678e44c0ceSJiri Pirko err |= mlxsw_sp_handle_feature(dev, features, NETIF_F_HW_TC,
12689454d930SJiri Pirko mlxsw_sp_feature_hw_tc);
12698e44c0ceSJiri Pirko err |= mlxsw_sp_handle_feature(dev, features, NETIF_F_LOOPBACK,
12708e44c0ceSJiri Pirko mlxsw_sp_feature_loopback);
12718e44c0ceSJiri Pirko
12728e44c0ceSJiri Pirko if (err) {
12738e44c0ceSJiri Pirko dev->features = oper_features;
12748e44c0ceSJiri Pirko return -EINVAL;
12758e44c0ceSJiri Pirko }
12768e44c0ceSJiri Pirko
12778e44c0ceSJiri Pirko return 0;
12789454d930SJiri Pirko }
12799454d930SJiri Pirko
mlxsw_sp_port_hwtstamp_set(struct mlxsw_sp_port * mlxsw_sp_port,struct ifreq * ifr)128087486427SPetr Machata static int mlxsw_sp_port_hwtstamp_set(struct mlxsw_sp_port *mlxsw_sp_port,
128187486427SPetr Machata struct ifreq *ifr)
128287486427SPetr Machata {
128387486427SPetr Machata struct hwtstamp_config config;
128487486427SPetr Machata int err;
128587486427SPetr Machata
128687486427SPetr Machata if (copy_from_user(&config, ifr->ifr_data, sizeof(config)))
128787486427SPetr Machata return -EFAULT;
128887486427SPetr Machata
128987486427SPetr Machata err = mlxsw_sp_port->mlxsw_sp->ptp_ops->hwtstamp_set(mlxsw_sp_port,
129087486427SPetr Machata &config);
129187486427SPetr Machata if (err)
129287486427SPetr Machata return err;
129387486427SPetr Machata
129487486427SPetr Machata if (copy_to_user(ifr->ifr_data, &config, sizeof(config)))
129587486427SPetr Machata return -EFAULT;
129687486427SPetr Machata
129787486427SPetr Machata return 0;
129887486427SPetr Machata }
129987486427SPetr Machata
mlxsw_sp_port_hwtstamp_get(struct mlxsw_sp_port * mlxsw_sp_port,struct ifreq * ifr)130087486427SPetr Machata static int mlxsw_sp_port_hwtstamp_get(struct mlxsw_sp_port *mlxsw_sp_port,
130187486427SPetr Machata struct ifreq *ifr)
130287486427SPetr Machata {
130387486427SPetr Machata struct hwtstamp_config config;
130487486427SPetr Machata int err;
130587486427SPetr Machata
130687486427SPetr Machata err = mlxsw_sp_port->mlxsw_sp->ptp_ops->hwtstamp_get(mlxsw_sp_port,
130787486427SPetr Machata &config);
130887486427SPetr Machata if (err)
130987486427SPetr Machata return err;
131087486427SPetr Machata
131187486427SPetr Machata if (copy_to_user(ifr->ifr_data, &config, sizeof(config)))
131287486427SPetr Machata return -EFAULT;
131387486427SPetr Machata
131487486427SPetr Machata return 0;
131587486427SPetr Machata }
131687486427SPetr Machata
mlxsw_sp_port_ptp_clear(struct mlxsw_sp_port * mlxsw_sp_port)131787486427SPetr Machata static inline void mlxsw_sp_port_ptp_clear(struct mlxsw_sp_port *mlxsw_sp_port)
131887486427SPetr Machata {
131987486427SPetr Machata struct hwtstamp_config config = {0};
132087486427SPetr Machata
132187486427SPetr Machata mlxsw_sp_port->mlxsw_sp->ptp_ops->hwtstamp_set(mlxsw_sp_port, &config);
132287486427SPetr Machata }
132387486427SPetr Machata
132487486427SPetr Machata static int
mlxsw_sp_port_ioctl(struct net_device * dev,struct ifreq * ifr,int cmd)132587486427SPetr Machata mlxsw_sp_port_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
132687486427SPetr Machata {
132787486427SPetr Machata struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(dev);
132887486427SPetr Machata
132987486427SPetr Machata switch (cmd) {
133087486427SPetr Machata case SIOCSHWTSTAMP:
133187486427SPetr Machata return mlxsw_sp_port_hwtstamp_set(mlxsw_sp_port, ifr);
133287486427SPetr Machata case SIOCGHWTSTAMP:
133387486427SPetr Machata return mlxsw_sp_port_hwtstamp_get(mlxsw_sp_port, ifr);
133487486427SPetr Machata default:
133587486427SPetr Machata return -EOPNOTSUPP;
133687486427SPetr Machata }
133787486427SPetr Machata }
133887486427SPetr Machata
133956ade8feSJiri Pirko static const struct net_device_ops mlxsw_sp_port_netdev_ops = {
134056ade8feSJiri Pirko .ndo_open = mlxsw_sp_port_open,
134156ade8feSJiri Pirko .ndo_stop = mlxsw_sp_port_stop,
134256ade8feSJiri Pirko .ndo_start_xmit = mlxsw_sp_port_xmit,
1343763b4b70SYotam Gigi .ndo_setup_tc = mlxsw_sp_setup_tc,
1344c5b9b518SJiri Pirko .ndo_set_rx_mode = mlxsw_sp_set_rx_mode,
134556ade8feSJiri Pirko .ndo_set_mac_address = mlxsw_sp_port_set_mac_address,
134656ade8feSJiri Pirko .ndo_change_mtu = mlxsw_sp_port_change_mtu,
134756ade8feSJiri Pirko .ndo_get_stats64 = mlxsw_sp_port_get_stats64,
1348fc1bbb0fSNogah Frankel .ndo_has_offload_stats = mlxsw_sp_port_has_offload_stats,
1349fc1bbb0fSNogah Frankel .ndo_get_offload_stats = mlxsw_sp_port_get_offload_stats,
135056ade8feSJiri Pirko .ndo_vlan_rx_add_vid = mlxsw_sp_port_add_vid,
135156ade8feSJiri Pirko .ndo_vlan_rx_kill_vid = mlxsw_sp_port_kill_vid,
13529454d930SJiri Pirko .ndo_set_features = mlxsw_sp_set_features,
1353a7605370SArnd Bergmann .ndo_eth_ioctl = mlxsw_sp_port_ioctl,
135456ade8feSJiri Pirko };
135556ade8feSJiri Pirko
135618f1e70cSIdo Schimmel static int
mlxsw_sp_port_speed_by_width_set(struct mlxsw_sp_port * mlxsw_sp_port)135735896d96SJiri Pirko mlxsw_sp_port_speed_by_width_set(struct mlxsw_sp_port *mlxsw_sp_port)
135818f1e70cSIdo Schimmel {
135918f1e70cSIdo Schimmel struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
1360b401ff85SIdo Schimmel u32 eth_proto_cap, eth_proto_admin, eth_proto_oper;
1361c5b870dfSShalom Toledo const struct mlxsw_sp_port_type_speed_ops *ops;
136218f1e70cSIdo Schimmel char ptys_pl[MLXSW_REG_PTYS_LEN];
13631601559bSAmit Cohen u32 eth_proto_cap_masked;
1364c5b870dfSShalom Toledo int err;
136518f1e70cSIdo Schimmel
1366c5b870dfSShalom Toledo ops = mlxsw_sp->port_type_speed_ops;
1367c5b870dfSShalom Toledo
13681601559bSAmit Cohen /* Set advertised speeds to speeds supported by both the driver
13691601559bSAmit Cohen * and the device.
13701601559bSAmit Cohen */
1371b401ff85SIdo Schimmel ops->reg_ptys_eth_pack(mlxsw_sp, ptys_pl, mlxsw_sp_port->local_port,
1372b401ff85SIdo Schimmel 0, false);
1373b401ff85SIdo Schimmel err = mlxsw_reg_query(mlxsw_sp->core, MLXSW_REG(ptys), ptys_pl);
1374c5b870dfSShalom Toledo if (err)
1375c5b870dfSShalom Toledo return err;
1376c5b870dfSShalom Toledo
1377b401ff85SIdo Schimmel ops->reg_ptys_eth_unpack(mlxsw_sp, ptys_pl, ð_proto_cap,
1378b401ff85SIdo Schimmel ð_proto_admin, ð_proto_oper);
13791601559bSAmit Cohen eth_proto_cap_masked = ops->ptys_proto_cap_masked_get(eth_proto_cap);
1380c5b870dfSShalom Toledo ops->reg_ptys_eth_pack(mlxsw_sp, ptys_pl, mlxsw_sp_port->local_port,
13811601559bSAmit Cohen eth_proto_cap_masked,
13821601559bSAmit Cohen mlxsw_sp_port->link.autoneg);
138318f1e70cSIdo Schimmel return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(ptys), ptys_pl);
138418f1e70cSIdo Schimmel }
138518f1e70cSIdo Schimmel
mlxsw_sp_port_speed_get(struct mlxsw_sp_port * mlxsw_sp_port,u32 * speed)1386ac9cc4e2SJiri Pirko int mlxsw_sp_port_speed_get(struct mlxsw_sp_port *mlxsw_sp_port, u32 *speed)
1387ac9cc4e2SJiri Pirko {
1388ac9cc4e2SJiri Pirko const struct mlxsw_sp_port_type_speed_ops *port_type_speed_ops;
1389ac9cc4e2SJiri Pirko struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
1390ac9cc4e2SJiri Pirko char ptys_pl[MLXSW_REG_PTYS_LEN];
1391ac9cc4e2SJiri Pirko u32 eth_proto_oper;
1392ac9cc4e2SJiri Pirko int err;
1393ac9cc4e2SJiri Pirko
1394ac9cc4e2SJiri Pirko port_type_speed_ops = mlxsw_sp->port_type_speed_ops;
1395ac9cc4e2SJiri Pirko port_type_speed_ops->reg_ptys_eth_pack(mlxsw_sp, ptys_pl,
1396ac9cc4e2SJiri Pirko mlxsw_sp_port->local_port, 0,
1397ac9cc4e2SJiri Pirko false);
1398ac9cc4e2SJiri Pirko err = mlxsw_reg_query(mlxsw_sp->core, MLXSW_REG(ptys), ptys_pl);
1399ac9cc4e2SJiri Pirko if (err)
1400ac9cc4e2SJiri Pirko return err;
1401ac9cc4e2SJiri Pirko port_type_speed_ops->reg_ptys_eth_unpack(mlxsw_sp, ptys_pl, NULL, NULL,
1402ac9cc4e2SJiri Pirko ð_proto_oper);
1403ac9cc4e2SJiri Pirko *speed = port_type_speed_ops->from_ptys_speed(mlxsw_sp, eth_proto_oper);
1404ac9cc4e2SJiri Pirko return 0;
1405ac9cc4e2SJiri Pirko }
1406ac9cc4e2SJiri Pirko
mlxsw_sp_port_ets_set(struct mlxsw_sp_port * mlxsw_sp_port,enum mlxsw_reg_qeec_hr hr,u8 index,u8 next_index,bool dwrr,u8 dwrr_weight)14078e8dfe9fSIdo Schimmel int mlxsw_sp_port_ets_set(struct mlxsw_sp_port *mlxsw_sp_port,
14088e8dfe9fSIdo Schimmel enum mlxsw_reg_qeec_hr hr, u8 index, u8 next_index,
14098e8dfe9fSIdo Schimmel bool dwrr, u8 dwrr_weight)
141090183b98SIdo Schimmel {
141190183b98SIdo Schimmel struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
141290183b98SIdo Schimmel char qeec_pl[MLXSW_REG_QEEC_LEN];
141390183b98SIdo Schimmel
141490183b98SIdo Schimmel mlxsw_reg_qeec_pack(qeec_pl, mlxsw_sp_port->local_port, hr, index,
141590183b98SIdo Schimmel next_index);
141690183b98SIdo Schimmel mlxsw_reg_qeec_de_set(qeec_pl, true);
141790183b98SIdo Schimmel mlxsw_reg_qeec_dwrr_set(qeec_pl, dwrr);
141890183b98SIdo Schimmel mlxsw_reg_qeec_dwrr_weight_set(qeec_pl, dwrr_weight);
141990183b98SIdo Schimmel return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(qeec), qeec_pl);
142090183b98SIdo Schimmel }
142190183b98SIdo Schimmel
mlxsw_sp_port_ets_maxrate_set(struct mlxsw_sp_port * mlxsw_sp_port,enum mlxsw_reg_qeec_hr hr,u8 index,u8 next_index,u32 maxrate,u8 burst_size)1422cc7cf517SIdo Schimmel int mlxsw_sp_port_ets_maxrate_set(struct mlxsw_sp_port *mlxsw_sp_port,
142390183b98SIdo Schimmel enum mlxsw_reg_qeec_hr hr, u8 index,
1424dbacf8baSPetr Machata u8 next_index, u32 maxrate, u8 burst_size)
142590183b98SIdo Schimmel {
142690183b98SIdo Schimmel struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
142790183b98SIdo Schimmel char qeec_pl[MLXSW_REG_QEEC_LEN];
142890183b98SIdo Schimmel
142990183b98SIdo Schimmel mlxsw_reg_qeec_pack(qeec_pl, mlxsw_sp_port->local_port, hr, index,
143090183b98SIdo Schimmel next_index);
143190183b98SIdo Schimmel mlxsw_reg_qeec_mase_set(qeec_pl, true);
143290183b98SIdo Schimmel mlxsw_reg_qeec_max_shaper_rate_set(qeec_pl, maxrate);
1433dbacf8baSPetr Machata mlxsw_reg_qeec_max_shaper_bs_set(qeec_pl, burst_size);
143490183b98SIdo Schimmel return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(qeec), qeec_pl);
143590183b98SIdo Schimmel }
143690183b98SIdo Schimmel
mlxsw_sp_port_min_bw_set(struct mlxsw_sp_port * mlxsw_sp_port,enum mlxsw_reg_qeec_hr hr,u8 index,u8 next_index,u32 minrate)14370fe64023SPetr Machata static int mlxsw_sp_port_min_bw_set(struct mlxsw_sp_port *mlxsw_sp_port,
14380fe64023SPetr Machata enum mlxsw_reg_qeec_hr hr, u8 index,
14390fe64023SPetr Machata u8 next_index, u32 minrate)
14400fe64023SPetr Machata {
14410fe64023SPetr Machata struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
14420fe64023SPetr Machata char qeec_pl[MLXSW_REG_QEEC_LEN];
14430fe64023SPetr Machata
14440fe64023SPetr Machata mlxsw_reg_qeec_pack(qeec_pl, mlxsw_sp_port->local_port, hr, index,
14450fe64023SPetr Machata next_index);
14460fe64023SPetr Machata mlxsw_reg_qeec_mise_set(qeec_pl, true);
14470fe64023SPetr Machata mlxsw_reg_qeec_min_shaper_rate_set(qeec_pl, minrate);
14480fe64023SPetr Machata
14490fe64023SPetr Machata return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(qeec), qeec_pl);
14500fe64023SPetr Machata }
14510fe64023SPetr Machata
mlxsw_sp_port_prio_tc_set(struct mlxsw_sp_port * mlxsw_sp_port,u8 switch_prio,u8 tclass)14528e8dfe9fSIdo Schimmel int mlxsw_sp_port_prio_tc_set(struct mlxsw_sp_port *mlxsw_sp_port,
145390183b98SIdo Schimmel u8 switch_prio, u8 tclass)
145490183b98SIdo Schimmel {
145590183b98SIdo Schimmel struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
145690183b98SIdo Schimmel char qtct_pl[MLXSW_REG_QTCT_LEN];
145790183b98SIdo Schimmel
145890183b98SIdo Schimmel mlxsw_reg_qtct_pack(qtct_pl, mlxsw_sp_port->local_port, switch_prio,
145990183b98SIdo Schimmel tclass);
146090183b98SIdo Schimmel return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(qtct), qtct_pl);
146190183b98SIdo Schimmel }
146290183b98SIdo Schimmel
mlxsw_sp_port_ets_init(struct mlxsw_sp_port * mlxsw_sp_port)146390183b98SIdo Schimmel static int mlxsw_sp_port_ets_init(struct mlxsw_sp_port *mlxsw_sp_port)
146490183b98SIdo Schimmel {
146590183b98SIdo Schimmel int err, i;
146690183b98SIdo Schimmel
146790183b98SIdo Schimmel /* Setup the elements hierarcy, so that each TC is linked to
146890183b98SIdo Schimmel * one subgroup, which are all member in the same group.
146990183b98SIdo Schimmel */
147090183b98SIdo Schimmel err = mlxsw_sp_port_ets_set(mlxsw_sp_port,
14719cf9b925SPetr Machata MLXSW_REG_QEEC_HR_GROUP, 0, 0, false, 0);
147290183b98SIdo Schimmel if (err)
147390183b98SIdo Schimmel return err;
147490183b98SIdo Schimmel for (i = 0; i < IEEE_8021QAZ_MAX_TCS; i++) {
147590183b98SIdo Schimmel err = mlxsw_sp_port_ets_set(mlxsw_sp_port,
14769cf9b925SPetr Machata MLXSW_REG_QEEC_HR_SUBGROUP, i,
147790183b98SIdo Schimmel 0, false, 0);
147890183b98SIdo Schimmel if (err)
147990183b98SIdo Schimmel return err;
148090183b98SIdo Schimmel }
148190183b98SIdo Schimmel for (i = 0; i < IEEE_8021QAZ_MAX_TCS; i++) {
148290183b98SIdo Schimmel err = mlxsw_sp_port_ets_set(mlxsw_sp_port,
14839cf9b925SPetr Machata MLXSW_REG_QEEC_HR_TC, i, i,
148490183b98SIdo Schimmel false, 0);
148590183b98SIdo Schimmel if (err)
148690183b98SIdo Schimmel return err;
14877b819530SPetr Machata
14887b819530SPetr Machata err = mlxsw_sp_port_ets_set(mlxsw_sp_port,
14899cf9b925SPetr Machata MLXSW_REG_QEEC_HR_TC,
14907b819530SPetr Machata i + 8, i,
1491f476b3f8SPetr Machata true, 100);
14927b819530SPetr Machata if (err)
14937b819530SPetr Machata return err;
149490183b98SIdo Schimmel }
149590183b98SIdo Schimmel
1496ea7bb579SShalom Toledo /* Make sure the max shaper is disabled in all hierarchies that support
1497ea7bb579SShalom Toledo * it. Note that this disables ptps (PTP shaper), but that is intended
1498ea7bb579SShalom Toledo * for the initial configuration.
149990183b98SIdo Schimmel */
150090183b98SIdo Schimmel err = mlxsw_sp_port_ets_maxrate_set(mlxsw_sp_port,
15019cf9b925SPetr Machata MLXSW_REG_QEEC_HR_PORT, 0, 0,
1502dbacf8baSPetr Machata MLXSW_REG_QEEC_MAS_DIS, 0);
150390183b98SIdo Schimmel if (err)
150490183b98SIdo Schimmel return err;
150590183b98SIdo Schimmel for (i = 0; i < IEEE_8021QAZ_MAX_TCS; i++) {
150690183b98SIdo Schimmel err = mlxsw_sp_port_ets_maxrate_set(mlxsw_sp_port,
15079cf9b925SPetr Machata MLXSW_REG_QEEC_HR_SUBGROUP,
150890183b98SIdo Schimmel i, 0,
1509dbacf8baSPetr Machata MLXSW_REG_QEEC_MAS_DIS, 0);
151090183b98SIdo Schimmel if (err)
151190183b98SIdo Schimmel return err;
151290183b98SIdo Schimmel }
151390183b98SIdo Schimmel for (i = 0; i < IEEE_8021QAZ_MAX_TCS; i++) {
151490183b98SIdo Schimmel err = mlxsw_sp_port_ets_maxrate_set(mlxsw_sp_port,
15159cf9b925SPetr Machata MLXSW_REG_QEEC_HR_TC,
151690183b98SIdo Schimmel i, i,
1517dbacf8baSPetr Machata MLXSW_REG_QEEC_MAS_DIS, 0);
151890183b98SIdo Schimmel if (err)
151990183b98SIdo Schimmel return err;
1520a9f36656SPetr Machata
1521a9f36656SPetr Machata err = mlxsw_sp_port_ets_maxrate_set(mlxsw_sp_port,
15229cf9b925SPetr Machata MLXSW_REG_QEEC_HR_TC,
1523a9f36656SPetr Machata i + 8, i,
1524dbacf8baSPetr Machata MLXSW_REG_QEEC_MAS_DIS, 0);
1525a9f36656SPetr Machata if (err)
1526a9f36656SPetr Machata return err;
152790183b98SIdo Schimmel }
152890183b98SIdo Schimmel
15290fe64023SPetr Machata /* Configure the min shaper for multicast TCs. */
15300fe64023SPetr Machata for (i = 0; i < IEEE_8021QAZ_MAX_TCS; i++) {
15310fe64023SPetr Machata err = mlxsw_sp_port_min_bw_set(mlxsw_sp_port,
15329cf9b925SPetr Machata MLXSW_REG_QEEC_HR_TC,
15330fe64023SPetr Machata i + 8, i,
15340fe64023SPetr Machata MLXSW_REG_QEEC_MIS_MIN);
15350fe64023SPetr Machata if (err)
15360fe64023SPetr Machata return err;
15370fe64023SPetr Machata }
15380fe64023SPetr Machata
153990183b98SIdo Schimmel /* Map all priorities to traffic class 0. */
154090183b98SIdo Schimmel for (i = 0; i < IEEE_8021QAZ_MAX_TCS; i++) {
154190183b98SIdo Schimmel err = mlxsw_sp_port_prio_tc_set(mlxsw_sp_port, i, 0);
154290183b98SIdo Schimmel if (err)
154390183b98SIdo Schimmel return err;
154490183b98SIdo Schimmel }
154590183b98SIdo Schimmel
154690183b98SIdo Schimmel return 0;
154790183b98SIdo Schimmel }
154890183b98SIdo Schimmel
mlxsw_sp_port_tc_mc_mode_set(struct mlxsw_sp_port * mlxsw_sp_port,bool enable)15497b819530SPetr Machata static int mlxsw_sp_port_tc_mc_mode_set(struct mlxsw_sp_port *mlxsw_sp_port,
15507b819530SPetr Machata bool enable)
15517b819530SPetr Machata {
15527b819530SPetr Machata struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
15537b819530SPetr Machata char qtctm_pl[MLXSW_REG_QTCTM_LEN];
15547b819530SPetr Machata
15557b819530SPetr Machata mlxsw_reg_qtctm_pack(qtctm_pl, mlxsw_sp_port->local_port, enable);
15567b819530SPetr Machata return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(qtctm), qtctm_pl);
15577b819530SPetr Machata }
15587b819530SPetr Machata
mlxsw_sp_port_overheat_init_val_set(struct mlxsw_sp_port * mlxsw_sp_port)15593bdbab3fSAmit Cohen static int mlxsw_sp_port_overheat_init_val_set(struct mlxsw_sp_port *mlxsw_sp_port)
15603bdbab3fSAmit Cohen {
15613bdbab3fSAmit Cohen struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
15626445eef0SJiri Pirko u8 slot_index = mlxsw_sp_port->mapping.slot_index;
15633bdbab3fSAmit Cohen u8 module = mlxsw_sp_port->mapping.module;
15643bdbab3fSAmit Cohen u64 overheat_counter;
15653bdbab3fSAmit Cohen int err;
15663bdbab3fSAmit Cohen
15676445eef0SJiri Pirko err = mlxsw_env_module_overheat_counter_get(mlxsw_sp->core, slot_index,
15686445eef0SJiri Pirko module, &overheat_counter);
15693bdbab3fSAmit Cohen if (err)
15703bdbab3fSAmit Cohen return err;
15713bdbab3fSAmit Cohen
15723bdbab3fSAmit Cohen mlxsw_sp_port->module_overheat_initial_val = overheat_counter;
15733bdbab3fSAmit Cohen return 0;
15743bdbab3fSAmit Cohen }
15753bdbab3fSAmit Cohen
157680dfeafdSAmit Cohen int
mlxsw_sp_port_vlan_classification_set(struct mlxsw_sp_port * mlxsw_sp_port,bool is_8021ad_tagged,bool is_8021q_tagged)1577a2ef3ae1SAmit Cohen mlxsw_sp_port_vlan_classification_set(struct mlxsw_sp_port *mlxsw_sp_port,
1578a2ef3ae1SAmit Cohen bool is_8021ad_tagged,
1579a2ef3ae1SAmit Cohen bool is_8021q_tagged)
1580a2ef3ae1SAmit Cohen {
1581a2ef3ae1SAmit Cohen struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
1582a2ef3ae1SAmit Cohen char spvc_pl[MLXSW_REG_SPVC_LEN];
1583a2ef3ae1SAmit Cohen
1584a2ef3ae1SAmit Cohen mlxsw_reg_spvc_pack(spvc_pl, mlxsw_sp_port->local_port,
1585a2ef3ae1SAmit Cohen is_8021ad_tagged, is_8021q_tagged);
1586a2ef3ae1SAmit Cohen return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(spvc), spvc_pl);
1587a2ef3ae1SAmit Cohen }
1588a2ef3ae1SAmit Cohen
mlxsw_sp_port_label_info_get(struct mlxsw_sp * mlxsw_sp,u16 local_port,u8 * port_number,u8 * split_port_subnumber,u8 * slot_index)15891dbfc9d7SJiri Pirko static int mlxsw_sp_port_label_info_get(struct mlxsw_sp *mlxsw_sp,
1590c934757dSAmit Cohen u16 local_port, u8 *port_number,
15911dbfc9d7SJiri Pirko u8 *split_port_subnumber,
15921dbfc9d7SJiri Pirko u8 *slot_index)
15931dbfc9d7SJiri Pirko {
15941dbfc9d7SJiri Pirko char pllp_pl[MLXSW_REG_PLLP_LEN];
15951dbfc9d7SJiri Pirko int err;
15961dbfc9d7SJiri Pirko
15971dbfc9d7SJiri Pirko mlxsw_reg_pllp_pack(pllp_pl, local_port);
15981dbfc9d7SJiri Pirko err = mlxsw_reg_query(mlxsw_sp->core, MLXSW_REG(pllp), pllp_pl);
15991dbfc9d7SJiri Pirko if (err)
16001dbfc9d7SJiri Pirko return err;
16011dbfc9d7SJiri Pirko mlxsw_reg_pllp_unpack(pllp_pl, port_number,
16021dbfc9d7SJiri Pirko split_port_subnumber, slot_index);
16031dbfc9d7SJiri Pirko return 0;
16041dbfc9d7SJiri Pirko }
16051dbfc9d7SJiri Pirko
mlxsw_sp_port_create(struct mlxsw_sp * mlxsw_sp,u16 local_port,bool split,struct mlxsw_sp_port_mapping * port_mapping)1606c934757dSAmit Cohen static int mlxsw_sp_port_create(struct mlxsw_sp *mlxsw_sp, u16 local_port,
160732ada69bSJiri Pirko bool split,
160835896d96SJiri Pirko struct mlxsw_sp_port_mapping *port_mapping)
160956ade8feSJiri Pirko {
1610c57529e1SIdo Schimmel struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan;
161156ade8feSJiri Pirko struct mlxsw_sp_port *mlxsw_sp_port;
1612622d3e92SDanielle Ratson u32 lanes = port_mapping->width;
16131dbfc9d7SJiri Pirko u8 split_port_subnumber;
161456ade8feSJiri Pirko struct net_device *dev;
16151dbfc9d7SJiri Pirko u8 port_number;
16161dbfc9d7SJiri Pirko u8 slot_index;
16171b604efbSDanielle Ratson bool splittable;
161856ade8feSJiri Pirko int err;
161956ade8feSJiri Pirko
162013eb056eSJiri Pirko err = mlxsw_sp_port_module_map(mlxsw_sp, local_port, port_mapping);
162113eb056eSJiri Pirko if (err) {
162213eb056eSJiri Pirko dev_err(mlxsw_sp->bus_info->dev, "Port %d: Failed to map module\n",
162313eb056eSJiri Pirko local_port);
162413eb056eSJiri Pirko return err;
162513eb056eSJiri Pirko }
162613eb056eSJiri Pirko
1627fec23861SJiri Pirko err = mlxsw_sp_port_swid_set(mlxsw_sp, local_port, 0);
1628fec23861SJiri Pirko if (err) {
1629fec23861SJiri Pirko dev_err(mlxsw_sp->bus_info->dev, "Port %d: Failed to set SWID\n",
1630fec23861SJiri Pirko local_port);
1631fec23861SJiri Pirko goto err_port_swid_set;
1632fec23861SJiri Pirko }
1633fec23861SJiri Pirko
16341dbfc9d7SJiri Pirko err = mlxsw_sp_port_label_info_get(mlxsw_sp, local_port, &port_number,
16351dbfc9d7SJiri Pirko &split_port_subnumber, &slot_index);
16361dbfc9d7SJiri Pirko if (err) {
16371dbfc9d7SJiri Pirko dev_err(mlxsw_sp->bus_info->dev, "Port %d: Failed to get port label information\n",
16381dbfc9d7SJiri Pirko local_port);
16391dbfc9d7SJiri Pirko goto err_port_label_info_get;
16401dbfc9d7SJiri Pirko }
16411dbfc9d7SJiri Pirko
16421b604efbSDanielle Ratson splittable = lanes > 1 && !split;
16436445eef0SJiri Pirko err = mlxsw_core_port_init(mlxsw_sp->core, local_port, slot_index,
16441dbfc9d7SJiri Pirko port_number, split, split_port_subnumber,
16451dbfc9d7SJiri Pirko splittable, lanes, mlxsw_sp->base_mac,
1646cdf29f4aSJiri Pirko sizeof(mlxsw_sp->base_mac));
16475b153859SIdo Schimmel if (err) {
16485b153859SIdo Schimmel dev_err(mlxsw_sp->bus_info->dev, "Port %d: Failed to init core port\n",
16495b153859SIdo Schimmel local_port);
165013eb056eSJiri Pirko goto err_core_port_init;
16515b153859SIdo Schimmel }
16525b153859SIdo Schimmel
165356ade8feSJiri Pirko dev = alloc_etherdev(sizeof(struct mlxsw_sp_port));
16545b153859SIdo Schimmel if (!dev) {
16555b153859SIdo Schimmel err = -ENOMEM;
16565b153859SIdo Schimmel goto err_alloc_etherdev;
16575b153859SIdo Schimmel }
1658f20a91f1SJiri Pirko SET_NETDEV_DEV(dev, mlxsw_sp->bus_info->dev);
16596b2a880fSJiri Pirko dev_net_set(dev, mlxsw_sp_net(mlxsw_sp));
166056ade8feSJiri Pirko mlxsw_sp_port = netdev_priv(dev);
1661ac73d4bfSJiri Pirko mlxsw_core_port_netdev_link(mlxsw_sp->core, local_port,
1662ac73d4bfSJiri Pirko mlxsw_sp_port, dev);
166356ade8feSJiri Pirko mlxsw_sp_port->dev = dev;
166456ade8feSJiri Pirko mlxsw_sp_port->mlxsw_sp = mlxsw_sp;
166556ade8feSJiri Pirko mlxsw_sp_port->local_port = local_port;
1666a2d2a205SIdo Schimmel mlxsw_sp_port->pvid = MLXSW_SP_DEFAULT_VID;
166718f1e70cSIdo Schimmel mlxsw_sp_port->split = split;
166835896d96SJiri Pirko mlxsw_sp_port->mapping = *port_mapping;
16690c83f88cSIdo Schimmel mlxsw_sp_port->link.autoneg = 1;
167031a08a52SIdo Schimmel INIT_LIST_HEAD(&mlxsw_sp_port->vlans_list);
167156ade8feSJiri Pirko
167256ade8feSJiri Pirko mlxsw_sp_port->pcpu_stats =
167356ade8feSJiri Pirko netdev_alloc_pcpu_stats(struct mlxsw_sp_port_pcpu_stats);
167456ade8feSJiri Pirko if (!mlxsw_sp_port->pcpu_stats) {
167556ade8feSJiri Pirko err = -ENOMEM;
167656ade8feSJiri Pirko goto err_alloc_stats;
167756ade8feSJiri Pirko }
167856ade8feSJiri Pirko
16799deef43dSNogah Frankel INIT_DELAYED_WORK(&mlxsw_sp_port->periodic_hw_stats.update_dw,
1680fc1bbb0fSNogah Frankel &update_stats_cache);
1681fc1bbb0fSNogah Frankel
168256ade8feSJiri Pirko dev->netdev_ops = &mlxsw_sp_port_netdev_ops;
168356ade8feSJiri Pirko dev->ethtool_ops = &mlxsw_sp_port_ethtool_ops;
168456ade8feSJiri Pirko
168556ade8feSJiri Pirko err = mlxsw_sp_port_dev_addr_init(mlxsw_sp_port);
168656ade8feSJiri Pirko if (err) {
168756ade8feSJiri Pirko dev_err(mlxsw_sp->bus_info->dev, "Port %d: Unable to init port mac address\n",
168856ade8feSJiri Pirko mlxsw_sp_port->local_port);
168956ade8feSJiri Pirko goto err_dev_addr_init;
169056ade8feSJiri Pirko }
169156ade8feSJiri Pirko
169256ade8feSJiri Pirko netif_carrier_off(dev);
169356ade8feSJiri Pirko
169456ade8feSJiri Pirko dev->features |= NETIF_F_NETNS_LOCAL | NETIF_F_LLTX | NETIF_F_SG |
1695763b4b70SYotam Gigi NETIF_F_HW_VLAN_CTAG_FILTER | NETIF_F_HW_TC;
16968e44c0ceSJiri Pirko dev->hw_features |= NETIF_F_HW_TC | NETIF_F_LOOPBACK;
169756ade8feSJiri Pirko
1698d894be57SJarod Wilson dev->min_mtu = 0;
1699d894be57SJarod Wilson dev->max_mtu = ETH_MAX_MTU;
1700d894be57SJarod Wilson
170156ade8feSJiri Pirko /* Each packet needs to have a Tx header (metadata) on top all other
170256ade8feSJiri Pirko * headers.
170356ade8feSJiri Pirko */
1704feb7d387SYotam Gigi dev->needed_headroom = MLXSW_TXHDR_LEN;
170556ade8feSJiri Pirko
170656ade8feSJiri Pirko err = mlxsw_sp_port_system_port_mapping_set(mlxsw_sp_port);
170756ade8feSJiri Pirko if (err) {
170856ade8feSJiri Pirko dev_err(mlxsw_sp->bus_info->dev, "Port %d: Failed to set system port mapping\n",
170956ade8feSJiri Pirko mlxsw_sp_port->local_port);
171056ade8feSJiri Pirko goto err_port_system_port_mapping_set;
171156ade8feSJiri Pirko }
171256ade8feSJiri Pirko
171335896d96SJiri Pirko err = mlxsw_sp_port_speed_by_width_set(mlxsw_sp_port);
171418f1e70cSIdo Schimmel if (err) {
171518f1e70cSIdo Schimmel dev_err(mlxsw_sp->bus_info->dev, "Port %d: Failed to enable speeds\n",
171618f1e70cSIdo Schimmel mlxsw_sp_port->local_port);
171718f1e70cSIdo Schimmel goto err_port_speed_by_width_set;
171818f1e70cSIdo Schimmel }
171918f1e70cSIdo Schimmel
17203232e8c6SPetr Machata err = mlxsw_sp->port_type_speed_ops->ptys_max_speed(mlxsw_sp_port,
17213232e8c6SPetr Machata &mlxsw_sp_port->max_speed);
17223232e8c6SPetr Machata if (err) {
17233232e8c6SPetr Machata dev_err(mlxsw_sp->bus_info->dev, "Port %d: Failed to get maximum speed\n",
17243232e8c6SPetr Machata mlxsw_sp_port->local_port);
17253232e8c6SPetr Machata goto err_max_speed_get;
17263232e8c6SPetr Machata }
17273232e8c6SPetr Machata
17282ecf87aeSPetr Machata err = mlxsw_sp_port_max_mtu_get(mlxsw_sp_port, &mlxsw_sp_port->max_mtu);
17292ecf87aeSPetr Machata if (err) {
17302ecf87aeSPetr Machata dev_err(mlxsw_sp->bus_info->dev, "Port %d: Failed to get maximum MTU\n",
17312ecf87aeSPetr Machata mlxsw_sp_port->local_port);
17322ecf87aeSPetr Machata goto err_port_max_mtu_get;
17332ecf87aeSPetr Machata }
17342ecf87aeSPetr Machata
173556ade8feSJiri Pirko err = mlxsw_sp_port_mtu_set(mlxsw_sp_port, ETH_DATA_LEN);
173656ade8feSJiri Pirko if (err) {
173756ade8feSJiri Pirko dev_err(mlxsw_sp->bus_info->dev, "Port %d: Failed to set MTU\n",
173856ade8feSJiri Pirko mlxsw_sp_port->local_port);
173956ade8feSJiri Pirko goto err_port_mtu_set;
174056ade8feSJiri Pirko }
174156ade8feSJiri Pirko
174256ade8feSJiri Pirko err = mlxsw_sp_port_admin_status_set(mlxsw_sp_port, false);
174356ade8feSJiri Pirko if (err)
174456ade8feSJiri Pirko goto err_port_admin_status_set;
174556ade8feSJiri Pirko
174656ade8feSJiri Pirko err = mlxsw_sp_port_buffers_init(mlxsw_sp_port);
174756ade8feSJiri Pirko if (err) {
174856ade8feSJiri Pirko dev_err(mlxsw_sp->bus_info->dev, "Port %d: Failed to initialize buffers\n",
174956ade8feSJiri Pirko mlxsw_sp_port->local_port);
175056ade8feSJiri Pirko goto err_port_buffers_init;
175156ade8feSJiri Pirko }
175256ade8feSJiri Pirko
175390183b98SIdo Schimmel err = mlxsw_sp_port_ets_init(mlxsw_sp_port);
175490183b98SIdo Schimmel if (err) {
175590183b98SIdo Schimmel dev_err(mlxsw_sp->bus_info->dev, "Port %d: Failed to initialize ETS\n",
175690183b98SIdo Schimmel mlxsw_sp_port->local_port);
175790183b98SIdo Schimmel goto err_port_ets_init;
175890183b98SIdo Schimmel }
175990183b98SIdo Schimmel
17607b819530SPetr Machata err = mlxsw_sp_port_tc_mc_mode_set(mlxsw_sp_port, true);
17617b819530SPetr Machata if (err) {
17627b819530SPetr Machata dev_err(mlxsw_sp->bus_info->dev, "Port %d: Failed to initialize TC MC mode\n",
17637b819530SPetr Machata mlxsw_sp_port->local_port);
17647b819530SPetr Machata goto err_port_tc_mc_mode;
17657b819530SPetr Machata }
17667b819530SPetr Machata
1767f00817dfSIdo Schimmel /* ETS and buffers must be initialized before DCB. */
1768f00817dfSIdo Schimmel err = mlxsw_sp_port_dcb_init(mlxsw_sp_port);
1769f00817dfSIdo Schimmel if (err) {
1770f00817dfSIdo Schimmel dev_err(mlxsw_sp->bus_info->dev, "Port %d: Failed to initialize DCB\n",
1771f00817dfSIdo Schimmel mlxsw_sp_port->local_port);
1772f00817dfSIdo Schimmel goto err_port_dcb_init;
1773f00817dfSIdo Schimmel }
1774f00817dfSIdo Schimmel
1775a1107487SIdo Schimmel err = mlxsw_sp_port_fids_init(mlxsw_sp_port);
177645a4a16cSIdo Schimmel if (err) {
1777a1107487SIdo Schimmel dev_err(mlxsw_sp->bus_info->dev, "Port %d: Failed to initialize FIDs\n",
177845a4a16cSIdo Schimmel mlxsw_sp_port->local_port);
1779a1107487SIdo Schimmel goto err_port_fids_init;
178045a4a16cSIdo Schimmel }
178145a4a16cSIdo Schimmel
1782371b437aSNogah Frankel err = mlxsw_sp_tc_qdisc_init(mlxsw_sp_port);
1783371b437aSNogah Frankel if (err) {
1784371b437aSNogah Frankel dev_err(mlxsw_sp->bus_info->dev, "Port %d: Failed to initialize TC qdiscs\n",
1785371b437aSNogah Frankel mlxsw_sp_port->local_port);
1786371b437aSNogah Frankel goto err_port_qdiscs_init;
1787371b437aSNogah Frankel }
1788371b437aSNogah Frankel
1789979b9b25SIdo Schimmel err = mlxsw_sp_port_vlan_set(mlxsw_sp_port, 0, VLAN_N_VID - 1, false,
1790979b9b25SIdo Schimmel false);
1791979b9b25SIdo Schimmel if (err) {
1792979b9b25SIdo Schimmel dev_err(mlxsw_sp->bus_info->dev, "Port %d: Failed to clear VLAN filter\n",
1793979b9b25SIdo Schimmel mlxsw_sp_port->local_port);
1794979b9b25SIdo Schimmel goto err_port_vlan_clear;
1795979b9b25SIdo Schimmel }
1796979b9b25SIdo Schimmel
17976e6030bdSIdo Schimmel err = mlxsw_sp_port_nve_init(mlxsw_sp_port);
17986e6030bdSIdo Schimmel if (err) {
17996e6030bdSIdo Schimmel dev_err(mlxsw_sp->bus_info->dev, "Port %d: Failed to initialize NVE\n",
18006e6030bdSIdo Schimmel mlxsw_sp_port->local_port);
18016e6030bdSIdo Schimmel goto err_port_nve_init;
18026e6030bdSIdo Schimmel }
18036e6030bdSIdo Schimmel
18043ae7a65bSAmit Cohen err = mlxsw_sp_port_pvid_set(mlxsw_sp_port, MLXSW_SP_DEFAULT_VID,
18053ae7a65bSAmit Cohen ETH_P_8021Q);
1806262e1ff9SIdo Schimmel if (err) {
1807262e1ff9SIdo Schimmel dev_err(mlxsw_sp->bus_info->dev, "Port %d: Failed to set PVID\n",
1808262e1ff9SIdo Schimmel mlxsw_sp_port->local_port);
1809262e1ff9SIdo Schimmel goto err_port_pvid_set;
1810262e1ff9SIdo Schimmel }
1811262e1ff9SIdo Schimmel
1812a2d2a205SIdo Schimmel mlxsw_sp_port_vlan = mlxsw_sp_port_vlan_create(mlxsw_sp_port,
1813a2d2a205SIdo Schimmel MLXSW_SP_DEFAULT_VID);
1814c57529e1SIdo Schimmel if (IS_ERR(mlxsw_sp_port_vlan)) {
1815c57529e1SIdo Schimmel dev_err(mlxsw_sp->bus_info->dev, "Port %d: Failed to create VID 1\n",
181605978481SIdo Schimmel mlxsw_sp_port->local_port);
1817d86fd113SWei Yongjun err = PTR_ERR(mlxsw_sp_port_vlan);
1818635c8c8bSIdo Schimmel goto err_port_vlan_create;
181905978481SIdo Schimmel }
1820346fca3bSIdo Schimmel mlxsw_sp_port->default_vlan = mlxsw_sp_port_vlan;
182105978481SIdo Schimmel
1822a2ef3ae1SAmit Cohen /* Set SPVC.et0=true and SPVC.et1=false to make the local port to treat
1823a2ef3ae1SAmit Cohen * only packets with 802.1q header as tagged packets.
1824a2ef3ae1SAmit Cohen */
1825a2ef3ae1SAmit Cohen err = mlxsw_sp_port_vlan_classification_set(mlxsw_sp_port, false, true);
1826a2ef3ae1SAmit Cohen if (err) {
1827a2ef3ae1SAmit Cohen dev_err(mlxsw_sp->bus_info->dev, "Port %d: Failed to set default VLAN classification\n",
1828a2ef3ae1SAmit Cohen local_port);
1829a2ef3ae1SAmit Cohen goto err_port_vlan_classification_set;
1830a2ef3ae1SAmit Cohen }
1831a2ef3ae1SAmit Cohen
18325fc17338SShalom Toledo INIT_DELAYED_WORK(&mlxsw_sp_port->ptp.shaper_dw,
18335fc17338SShalom Toledo mlxsw_sp->ptp_ops->shaper_work);
18345fc17338SShalom Toledo
18352f25844cSIdo Schimmel mlxsw_sp->ports[local_port] = mlxsw_sp_port;
18363bdbab3fSAmit Cohen
18373bdbab3fSAmit Cohen err = mlxsw_sp_port_overheat_init_val_set(mlxsw_sp_port);
18383bdbab3fSAmit Cohen if (err) {
18393bdbab3fSAmit Cohen dev_err(mlxsw_sp->bus_info->dev, "Port %d: Failed to set overheat initial value\n",
18403bdbab3fSAmit Cohen mlxsw_sp_port->local_port);
18413bdbab3fSAmit Cohen goto err_port_overheat_init_val_set;
18423bdbab3fSAmit Cohen }
18433bdbab3fSAmit Cohen
184456ade8feSJiri Pirko err = register_netdev(dev);
184556ade8feSJiri Pirko if (err) {
184656ade8feSJiri Pirko dev_err(mlxsw_sp->bus_info->dev, "Port %d: Failed to register netdev\n",
184756ade8feSJiri Pirko mlxsw_sp_port->local_port);
184856ade8feSJiri Pirko goto err_register_netdev;
184956ade8feSJiri Pirko }
185056ade8feSJiri Pirko
18519deef43dSNogah Frankel mlxsw_core_schedule_dw(&mlxsw_sp_port->periodic_hw_stats.update_dw, 0);
185256ade8feSJiri Pirko return 0;
185356ade8feSJiri Pirko
185456ade8feSJiri Pirko err_register_netdev:
18553bdbab3fSAmit Cohen err_port_overheat_init_val_set:
1856a2ef3ae1SAmit Cohen mlxsw_sp_port_vlan_classification_set(mlxsw_sp_port, true, true);
1857a2ef3ae1SAmit Cohen err_port_vlan_classification_set:
18582f25844cSIdo Schimmel mlxsw_sp->ports[local_port] = NULL;
1859635c8c8bSIdo Schimmel mlxsw_sp_port_vlan_destroy(mlxsw_sp_port_vlan);
1860635c8c8bSIdo Schimmel err_port_vlan_create:
1861262e1ff9SIdo Schimmel err_port_pvid_set:
18626e6030bdSIdo Schimmel mlxsw_sp_port_nve_fini(mlxsw_sp_port);
18636e6030bdSIdo Schimmel err_port_nve_init:
1864979b9b25SIdo Schimmel err_port_vlan_clear:
1865371b437aSNogah Frankel mlxsw_sp_tc_qdisc_fini(mlxsw_sp_port);
1866371b437aSNogah Frankel err_port_qdiscs_init:
1867a1107487SIdo Schimmel mlxsw_sp_port_fids_fini(mlxsw_sp_port);
1868a1107487SIdo Schimmel err_port_fids_init:
18694de34eb5SIdo Schimmel mlxsw_sp_port_dcb_fini(mlxsw_sp_port);
1870f00817dfSIdo Schimmel err_port_dcb_init:
18717b819530SPetr Machata mlxsw_sp_port_tc_mc_mode_set(mlxsw_sp_port, false);
18727b819530SPetr Machata err_port_tc_mc_mode:
187390183b98SIdo Schimmel err_port_ets_init:
18743a77f5a2SPetr Machata mlxsw_sp_port_buffers_fini(mlxsw_sp_port);
187556ade8feSJiri Pirko err_port_buffers_init:
187656ade8feSJiri Pirko err_port_admin_status_set:
187756ade8feSJiri Pirko err_port_mtu_set:
18782ecf87aeSPetr Machata err_port_max_mtu_get:
18793232e8c6SPetr Machata err_max_speed_get:
188018f1e70cSIdo Schimmel err_port_speed_by_width_set:
188156ade8feSJiri Pirko err_port_system_port_mapping_set:
188256ade8feSJiri Pirko err_dev_addr_init:
188356ade8feSJiri Pirko free_percpu(mlxsw_sp_port->pcpu_stats);
188456ade8feSJiri Pirko err_alloc_stats:
188556ade8feSJiri Pirko free_netdev(dev);
18865b153859SIdo Schimmel err_alloc_etherdev:
188767963a33SJiri Pirko mlxsw_core_port_fini(mlxsw_sp->core, local_port);
188813eb056eSJiri Pirko err_core_port_init:
18891dbfc9d7SJiri Pirko err_port_label_info_get:
1890fec23861SJiri Pirko mlxsw_sp_port_swid_set(mlxsw_sp, local_port,
1891fec23861SJiri Pirko MLXSW_PORT_SWID_DISABLED_PORT);
1892fec23861SJiri Pirko err_port_swid_set:
18936445eef0SJiri Pirko mlxsw_sp_port_module_unmap(mlxsw_sp, local_port,
18946445eef0SJiri Pirko port_mapping->slot_index,
189534945452SVadim Pasternak port_mapping->module);
189667963a33SJiri Pirko return err;
189767963a33SJiri Pirko }
189867963a33SJiri Pirko
mlxsw_sp_port_remove(struct mlxsw_sp * mlxsw_sp,u16 local_port)1899c934757dSAmit Cohen static void mlxsw_sp_port_remove(struct mlxsw_sp *mlxsw_sp, u16 local_port)
190056ade8feSJiri Pirko {
190156ade8feSJiri Pirko struct mlxsw_sp_port *mlxsw_sp_port = mlxsw_sp->ports[local_port];
19026445eef0SJiri Pirko u8 slot_index = mlxsw_sp_port->mapping.slot_index;
1903896f399bSIdo Schimmel u8 module = mlxsw_sp_port->mapping.module;
190456ade8feSJiri Pirko
19059deef43dSNogah Frankel cancel_delayed_work_sync(&mlxsw_sp_port->periodic_hw_stats.update_dw);
19065fc17338SShalom Toledo cancel_delayed_work_sync(&mlxsw_sp_port->ptp.shaper_dw);
190756ade8feSJiri Pirko unregister_netdev(mlxsw_sp_port->dev); /* This calls ndo_stop */
1908a159e986SAmit Cohen mlxsw_sp_port_ptp_clear(mlxsw_sp_port);
1909a2ef3ae1SAmit Cohen mlxsw_sp_port_vlan_classification_set(mlxsw_sp_port, true, true);
19102f25844cSIdo Schimmel mlxsw_sp->ports[local_port] = NULL;
1911ab6c3b79SIdo Schimmel mlxsw_sp_port_vlan_flush(mlxsw_sp_port, true);
19126e6030bdSIdo Schimmel mlxsw_sp_port_nve_fini(mlxsw_sp_port);
1913371b437aSNogah Frankel mlxsw_sp_tc_qdisc_fini(mlxsw_sp_port);
1914a1107487SIdo Schimmel mlxsw_sp_port_fids_fini(mlxsw_sp_port);
1915f00817dfSIdo Schimmel mlxsw_sp_port_dcb_fini(mlxsw_sp_port);
19167b819530SPetr Machata mlxsw_sp_port_tc_mc_mode_set(mlxsw_sp_port, false);
19173a77f5a2SPetr Machata mlxsw_sp_port_buffers_fini(mlxsw_sp_port);
1918136f1445SYotam Gigi free_percpu(mlxsw_sp_port->pcpu_stats);
191931a08a52SIdo Schimmel WARN_ON_ONCE(!list_empty(&mlxsw_sp_port->vlans_list));
192056ade8feSJiri Pirko free_netdev(mlxsw_sp_port->dev);
192167963a33SJiri Pirko mlxsw_core_port_fini(mlxsw_sp->core, local_port);
1922fec23861SJiri Pirko mlxsw_sp_port_swid_set(mlxsw_sp, local_port,
1923fec23861SJiri Pirko MLXSW_PORT_SWID_DISABLED_PORT);
19246445eef0SJiri Pirko mlxsw_sp_port_module_unmap(mlxsw_sp, local_port, slot_index, module);
192567963a33SJiri Pirko }
192667963a33SJiri Pirko
mlxsw_sp_cpu_port_create(struct mlxsw_sp * mlxsw_sp)192728b1987eSShalom Toledo static int mlxsw_sp_cpu_port_create(struct mlxsw_sp *mlxsw_sp)
192828b1987eSShalom Toledo {
192928b1987eSShalom Toledo struct mlxsw_sp_port *mlxsw_sp_port;
193028b1987eSShalom Toledo int err;
193128b1987eSShalom Toledo
193228b1987eSShalom Toledo mlxsw_sp_port = kzalloc(sizeof(*mlxsw_sp_port), GFP_KERNEL);
193328b1987eSShalom Toledo if (!mlxsw_sp_port)
193428b1987eSShalom Toledo return -ENOMEM;
193528b1987eSShalom Toledo
193628b1987eSShalom Toledo mlxsw_sp_port->mlxsw_sp = mlxsw_sp;
193728b1987eSShalom Toledo mlxsw_sp_port->local_port = MLXSW_PORT_CPU_PORT;
193828b1987eSShalom Toledo
193928b1987eSShalom Toledo err = mlxsw_core_cpu_port_init(mlxsw_sp->core,
194028b1987eSShalom Toledo mlxsw_sp_port,
194128b1987eSShalom Toledo mlxsw_sp->base_mac,
194228b1987eSShalom Toledo sizeof(mlxsw_sp->base_mac));
194328b1987eSShalom Toledo if (err) {
194428b1987eSShalom Toledo dev_err(mlxsw_sp->bus_info->dev, "Failed to initialize core CPU port\n");
194528b1987eSShalom Toledo goto err_core_cpu_port_init;
194628b1987eSShalom Toledo }
194728b1987eSShalom Toledo
194828b1987eSShalom Toledo mlxsw_sp->ports[MLXSW_PORT_CPU_PORT] = mlxsw_sp_port;
194928b1987eSShalom Toledo return 0;
195028b1987eSShalom Toledo
195128b1987eSShalom Toledo err_core_cpu_port_init:
195228b1987eSShalom Toledo kfree(mlxsw_sp_port);
195328b1987eSShalom Toledo return err;
195428b1987eSShalom Toledo }
195528b1987eSShalom Toledo
mlxsw_sp_cpu_port_remove(struct mlxsw_sp * mlxsw_sp)195628b1987eSShalom Toledo static void mlxsw_sp_cpu_port_remove(struct mlxsw_sp *mlxsw_sp)
195728b1987eSShalom Toledo {
195828b1987eSShalom Toledo struct mlxsw_sp_port *mlxsw_sp_port =
195928b1987eSShalom Toledo mlxsw_sp->ports[MLXSW_PORT_CPU_PORT];
196028b1987eSShalom Toledo
196128b1987eSShalom Toledo mlxsw_core_cpu_port_fini(mlxsw_sp->core);
196228b1987eSShalom Toledo mlxsw_sp->ports[MLXSW_PORT_CPU_PORT] = NULL;
196328b1987eSShalom Toledo kfree(mlxsw_sp_port);
196428b1987eSShalom Toledo }
196528b1987eSShalom Toledo
mlxsw_sp_local_port_valid(u16 local_port)1966c934757dSAmit Cohen static bool mlxsw_sp_local_port_valid(u16 local_port)
196732ada69bSJiri Pirko {
196832ada69bSJiri Pirko return local_port != MLXSW_PORT_CPU_PORT;
196932ada69bSJiri Pirko }
197032ada69bSJiri Pirko
mlxsw_sp_port_created(struct mlxsw_sp * mlxsw_sp,u16 local_port)1971c934757dSAmit Cohen static bool mlxsw_sp_port_created(struct mlxsw_sp *mlxsw_sp, u16 local_port)
1972f83e2102SJiri Pirko {
197332ada69bSJiri Pirko if (!mlxsw_sp_local_port_valid(local_port))
197432ada69bSJiri Pirko return false;
1975f83e2102SJiri Pirko return mlxsw_sp->ports[local_port] != NULL;
1976f83e2102SJiri Pirko }
1977f83e2102SJiri Pirko
mlxsw_sp_port_mapping_event_set(struct mlxsw_sp * mlxsw_sp,u16 local_port,bool enable)1978b0ec003eSJiri Pirko static int mlxsw_sp_port_mapping_event_set(struct mlxsw_sp *mlxsw_sp,
1979b0ec003eSJiri Pirko u16 local_port, bool enable)
1980b0ec003eSJiri Pirko {
1981b0ec003eSJiri Pirko char pmecr_pl[MLXSW_REG_PMECR_LEN];
1982b0ec003eSJiri Pirko
1983b0ec003eSJiri Pirko mlxsw_reg_pmecr_pack(pmecr_pl, local_port,
1984b0ec003eSJiri Pirko enable ? MLXSW_REG_PMECR_E_GENERATE_EVENT :
1985b0ec003eSJiri Pirko MLXSW_REG_PMECR_E_DO_NOT_GENERATE_EVENT);
1986b0ec003eSJiri Pirko return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(pmecr), pmecr_pl);
1987b0ec003eSJiri Pirko }
1988b0ec003eSJiri Pirko
1989b0ec003eSJiri Pirko struct mlxsw_sp_port_mapping_event {
1990b0ec003eSJiri Pirko struct list_head list;
1991b0ec003eSJiri Pirko char pmlp_pl[MLXSW_REG_PMLP_LEN];
1992b0ec003eSJiri Pirko };
1993b0ec003eSJiri Pirko
mlxsw_sp_port_mapping_events_work(struct work_struct * work)1994b0ec003eSJiri Pirko static void mlxsw_sp_port_mapping_events_work(struct work_struct *work)
1995b0ec003eSJiri Pirko {
1996b0ec003eSJiri Pirko struct mlxsw_sp_port_mapping_event *event, *next_event;
1997b0ec003eSJiri Pirko struct mlxsw_sp_port_mapping_events *events;
1998b0ec003eSJiri Pirko struct mlxsw_sp_port_mapping port_mapping;
1999b0ec003eSJiri Pirko struct mlxsw_sp *mlxsw_sp;
2000b0ec003eSJiri Pirko struct devlink *devlink;
2001b0ec003eSJiri Pirko LIST_HEAD(event_queue);
2002b0ec003eSJiri Pirko u16 local_port;
2003b0ec003eSJiri Pirko int err;
2004b0ec003eSJiri Pirko
2005b0ec003eSJiri Pirko events = container_of(work, struct mlxsw_sp_port_mapping_events, work);
2006b0ec003eSJiri Pirko mlxsw_sp = container_of(events, struct mlxsw_sp, port_mapping_events);
2007b0ec003eSJiri Pirko devlink = priv_to_devlink(mlxsw_sp->core);
2008b0ec003eSJiri Pirko
2009b0ec003eSJiri Pirko spin_lock_bh(&events->queue_lock);
2010b0ec003eSJiri Pirko list_splice_init(&events->queue, &event_queue);
2011b0ec003eSJiri Pirko spin_unlock_bh(&events->queue_lock);
2012b0ec003eSJiri Pirko
2013b0ec003eSJiri Pirko list_for_each_entry_safe(event, next_event, &event_queue, list) {
2014b0ec003eSJiri Pirko local_port = mlxsw_reg_pmlp_local_port_get(event->pmlp_pl);
2015b0ec003eSJiri Pirko err = mlxsw_sp_port_module_info_parse(mlxsw_sp, local_port,
2016b0ec003eSJiri Pirko event->pmlp_pl, &port_mapping);
2017b0ec003eSJiri Pirko if (err)
2018b0ec003eSJiri Pirko goto out;
2019b0ec003eSJiri Pirko
2020b0ec003eSJiri Pirko if (WARN_ON_ONCE(!port_mapping.width))
2021b0ec003eSJiri Pirko goto out;
2022b0ec003eSJiri Pirko
2023b0ec003eSJiri Pirko devl_lock(devlink);
2024b0ec003eSJiri Pirko
2025b0ec003eSJiri Pirko if (!mlxsw_sp_port_created(mlxsw_sp, local_port))
2026b0ec003eSJiri Pirko mlxsw_sp_port_create(mlxsw_sp, local_port,
2027b0ec003eSJiri Pirko false, &port_mapping);
2028b0ec003eSJiri Pirko else
2029b0ec003eSJiri Pirko WARN_ON_ONCE(1);
2030b0ec003eSJiri Pirko
2031b0ec003eSJiri Pirko devl_unlock(devlink);
2032b0ec003eSJiri Pirko
2033b0ec003eSJiri Pirko mlxsw_sp->port_mapping[local_port] = port_mapping;
2034b0ec003eSJiri Pirko
2035b0ec003eSJiri Pirko out:
2036b0ec003eSJiri Pirko kfree(event);
2037b0ec003eSJiri Pirko }
2038b0ec003eSJiri Pirko }
2039b0ec003eSJiri Pirko
2040b0ec003eSJiri Pirko static void
mlxsw_sp_port_mapping_listener_func(const struct mlxsw_reg_info * reg,char * pmlp_pl,void * priv)2041b0ec003eSJiri Pirko mlxsw_sp_port_mapping_listener_func(const struct mlxsw_reg_info *reg,
2042b0ec003eSJiri Pirko char *pmlp_pl, void *priv)
2043b0ec003eSJiri Pirko {
2044b0ec003eSJiri Pirko struct mlxsw_sp_port_mapping_events *events;
2045b0ec003eSJiri Pirko struct mlxsw_sp_port_mapping_event *event;
2046b0ec003eSJiri Pirko struct mlxsw_sp *mlxsw_sp = priv;
2047b0ec003eSJiri Pirko u16 local_port;
2048b0ec003eSJiri Pirko
2049b0ec003eSJiri Pirko local_port = mlxsw_reg_pmlp_local_port_get(pmlp_pl);
2050b0ec003eSJiri Pirko if (WARN_ON_ONCE(!mlxsw_sp_local_port_is_valid(mlxsw_sp, local_port)))
2051b0ec003eSJiri Pirko return;
2052b0ec003eSJiri Pirko
2053b0ec003eSJiri Pirko events = &mlxsw_sp->port_mapping_events;
2054b0ec003eSJiri Pirko event = kmalloc(sizeof(*event), GFP_ATOMIC);
2055b0ec003eSJiri Pirko if (!event)
2056b0ec003eSJiri Pirko return;
2057b0ec003eSJiri Pirko memcpy(event->pmlp_pl, pmlp_pl, sizeof(event->pmlp_pl));
2058b0ec003eSJiri Pirko spin_lock(&events->queue_lock);
2059b0ec003eSJiri Pirko list_add_tail(&event->list, &events->queue);
2060b0ec003eSJiri Pirko spin_unlock(&events->queue_lock);
2061b0ec003eSJiri Pirko mlxsw_core_schedule_work(&events->work);
2062b0ec003eSJiri Pirko }
2063b0ec003eSJiri Pirko
2064b0ec003eSJiri Pirko static void
__mlxsw_sp_port_mapping_events_cancel(struct mlxsw_sp * mlxsw_sp)2065b0ec003eSJiri Pirko __mlxsw_sp_port_mapping_events_cancel(struct mlxsw_sp *mlxsw_sp)
2066b0ec003eSJiri Pirko {
2067b0ec003eSJiri Pirko struct mlxsw_sp_port_mapping_event *event, *next_event;
2068b0ec003eSJiri Pirko struct mlxsw_sp_port_mapping_events *events;
2069b0ec003eSJiri Pirko
2070b0ec003eSJiri Pirko events = &mlxsw_sp->port_mapping_events;
2071b0ec003eSJiri Pirko
2072b0ec003eSJiri Pirko /* Caller needs to make sure that no new event is going to appear. */
2073b0ec003eSJiri Pirko cancel_work_sync(&events->work);
2074b0ec003eSJiri Pirko list_for_each_entry_safe(event, next_event, &events->queue, list) {
2075b0ec003eSJiri Pirko list_del(&event->list);
2076b0ec003eSJiri Pirko kfree(event);
2077b0ec003eSJiri Pirko }
2078b0ec003eSJiri Pirko }
2079b0ec003eSJiri Pirko
mlxsw_sp_ports_remove(struct mlxsw_sp * mlxsw_sp)208056ade8feSJiri Pirko static void mlxsw_sp_ports_remove(struct mlxsw_sp *mlxsw_sp)
208156ade8feSJiri Pirko {
2082b0ec003eSJiri Pirko unsigned int max_ports = mlxsw_core_max_ports(mlxsw_sp->core);
208356ade8feSJiri Pirko int i;
208456ade8feSJiri Pirko
2085b0ec003eSJiri Pirko for (i = 1; i < max_ports; i++)
2086b0ec003eSJiri Pirko mlxsw_sp_port_mapping_event_set(mlxsw_sp, i, false);
2087b0ec003eSJiri Pirko /* Make sure all scheduled events are processed */
2088b0ec003eSJiri Pirko __mlxsw_sp_port_mapping_events_cancel(mlxsw_sp);
2089b0ec003eSJiri Pirko
2090b0ec003eSJiri Pirko for (i = 1; i < max_ports; i++)
2091f83e2102SJiri Pirko if (mlxsw_sp_port_created(mlxsw_sp, i))
209256ade8feSJiri Pirko mlxsw_sp_port_remove(mlxsw_sp, i);
209328b1987eSShalom Toledo mlxsw_sp_cpu_port_remove(mlxsw_sp);
209456ade8feSJiri Pirko kfree(mlxsw_sp->ports);
20954340f42fSJiri Pirko mlxsw_sp->ports = NULL;
209656ade8feSJiri Pirko }
209756ade8feSJiri Pirko
209845bf3b72SJiri Pirko static void
mlxsw_sp_ports_remove_selected(struct mlxsw_core * mlxsw_core,bool (* selector)(void * priv,u16 local_port),void * priv)209945bf3b72SJiri Pirko mlxsw_sp_ports_remove_selected(struct mlxsw_core *mlxsw_core,
210045bf3b72SJiri Pirko bool (*selector)(void *priv, u16 local_port),
210145bf3b72SJiri Pirko void *priv)
210245bf3b72SJiri Pirko {
210345bf3b72SJiri Pirko struct mlxsw_sp *mlxsw_sp = mlxsw_core_driver_priv(mlxsw_core);
210445bf3b72SJiri Pirko unsigned int max_ports = mlxsw_core_max_ports(mlxsw_core);
210545bf3b72SJiri Pirko int i;
210645bf3b72SJiri Pirko
210745bf3b72SJiri Pirko for (i = 1; i < max_ports; i++)
210845bf3b72SJiri Pirko if (mlxsw_sp_port_created(mlxsw_sp, i) && selector(priv, i))
210945bf3b72SJiri Pirko mlxsw_sp_port_remove(mlxsw_sp, i);
211045bf3b72SJiri Pirko }
211145bf3b72SJiri Pirko
mlxsw_sp_ports_create(struct mlxsw_sp * mlxsw_sp)211256ade8feSJiri Pirko static int mlxsw_sp_ports_create(struct mlxsw_sp *mlxsw_sp)
211356ade8feSJiri Pirko {
21145ec2ee7dSIdo Schimmel unsigned int max_ports = mlxsw_core_max_ports(mlxsw_sp->core);
2115b0ec003eSJiri Pirko struct mlxsw_sp_port_mapping_events *events;
21164a7f970fSJiri Pirko struct mlxsw_sp_port_mapping *port_mapping;
211756ade8feSJiri Pirko size_t alloc_size;
211856ade8feSJiri Pirko int i;
211956ade8feSJiri Pirko int err;
212056ade8feSJiri Pirko
21215ec2ee7dSIdo Schimmel alloc_size = sizeof(struct mlxsw_sp_port *) * max_ports;
212256ade8feSJiri Pirko mlxsw_sp->ports = kzalloc(alloc_size, GFP_KERNEL);
212356ade8feSJiri Pirko if (!mlxsw_sp->ports)
212456ade8feSJiri Pirko return -ENOMEM;
212556ade8feSJiri Pirko
2126b0ec003eSJiri Pirko events = &mlxsw_sp->port_mapping_events;
2127b0ec003eSJiri Pirko INIT_LIST_HEAD(&events->queue);
2128b0ec003eSJiri Pirko spin_lock_init(&events->queue_lock);
2129b0ec003eSJiri Pirko INIT_WORK(&events->work, mlxsw_sp_port_mapping_events_work);
2130b0ec003eSJiri Pirko
2131b0ec003eSJiri Pirko for (i = 1; i < max_ports; i++) {
2132b0ec003eSJiri Pirko err = mlxsw_sp_port_mapping_event_set(mlxsw_sp, i, true);
2133b0ec003eSJiri Pirko if (err)
2134b0ec003eSJiri Pirko goto err_event_enable;
2135b0ec003eSJiri Pirko }
2136b0ec003eSJiri Pirko
213728b1987eSShalom Toledo err = mlxsw_sp_cpu_port_create(mlxsw_sp);
213828b1987eSShalom Toledo if (err)
213928b1987eSShalom Toledo goto err_cpu_port_create;
214028b1987eSShalom Toledo
21415ec2ee7dSIdo Schimmel for (i = 1; i < max_ports; i++) {
2142d3ad2d88SJiri Pirko port_mapping = &mlxsw_sp->port_mapping[i];
2143d3ad2d88SJiri Pirko if (!port_mapping->width)
2144558c2d5eSIdo Schimmel continue;
214532ada69bSJiri Pirko err = mlxsw_sp_port_create(mlxsw_sp, i, false, port_mapping);
214656ade8feSJiri Pirko if (err)
214756ade8feSJiri Pirko goto err_port_create;
214856ade8feSJiri Pirko }
214956ade8feSJiri Pirko return 0;
215056ade8feSJiri Pirko
215156ade8feSJiri Pirko err_port_create:
215256ade8feSJiri Pirko for (i--; i >= 1; i--)
2153f83e2102SJiri Pirko if (mlxsw_sp_port_created(mlxsw_sp, i))
215456ade8feSJiri Pirko mlxsw_sp_port_remove(mlxsw_sp, i);
2155b0ec003eSJiri Pirko i = max_ports;
215628b1987eSShalom Toledo mlxsw_sp_cpu_port_remove(mlxsw_sp);
215728b1987eSShalom Toledo err_cpu_port_create:
2158b0ec003eSJiri Pirko err_event_enable:
2159b0ec003eSJiri Pirko for (i--; i >= 1; i--)
2160b0ec003eSJiri Pirko mlxsw_sp_port_mapping_event_set(mlxsw_sp, i, false);
2161b0ec003eSJiri Pirko /* Make sure all scheduled events are processed */
2162b0ec003eSJiri Pirko __mlxsw_sp_port_mapping_events_cancel(mlxsw_sp);
216356ade8feSJiri Pirko kfree(mlxsw_sp->ports);
21644340f42fSJiri Pirko mlxsw_sp->ports = NULL;
216556ade8feSJiri Pirko return err;
216656ade8feSJiri Pirko }
216756ade8feSJiri Pirko
mlxsw_sp_port_module_info_init(struct mlxsw_sp * mlxsw_sp)21684a7f970fSJiri Pirko static int mlxsw_sp_port_module_info_init(struct mlxsw_sp *mlxsw_sp)
21694a7f970fSJiri Pirko {
21704a7f970fSJiri Pirko unsigned int max_ports = mlxsw_core_max_ports(mlxsw_sp->core);
2171d3ad2d88SJiri Pirko struct mlxsw_sp_port_mapping *port_mapping;
21724a7f970fSJiri Pirko int i;
21734a7f970fSJiri Pirko int err;
21744a7f970fSJiri Pirko
21754a7f970fSJiri Pirko mlxsw_sp->port_mapping = kcalloc(max_ports,
2176d3ad2d88SJiri Pirko sizeof(struct mlxsw_sp_port_mapping),
21774a7f970fSJiri Pirko GFP_KERNEL);
21784a7f970fSJiri Pirko if (!mlxsw_sp->port_mapping)
21794a7f970fSJiri Pirko return -ENOMEM;
21804a7f970fSJiri Pirko
21814a7f970fSJiri Pirko for (i = 1; i < max_ports; i++) {
2182d3ad2d88SJiri Pirko port_mapping = &mlxsw_sp->port_mapping[i];
2183d3ad2d88SJiri Pirko err = mlxsw_sp_port_module_info_get(mlxsw_sp, i, port_mapping);
21844a7f970fSJiri Pirko if (err)
21854a7f970fSJiri Pirko goto err_port_module_info_get;
2186630d4e75SWei Yongjun }
21874a7f970fSJiri Pirko return 0;
21884a7f970fSJiri Pirko
21894a7f970fSJiri Pirko err_port_module_info_get:
21904a7f970fSJiri Pirko kfree(mlxsw_sp->port_mapping);
21914a7f970fSJiri Pirko return err;
21924a7f970fSJiri Pirko }
21934a7f970fSJiri Pirko
mlxsw_sp_port_module_info_fini(struct mlxsw_sp * mlxsw_sp)21944a7f970fSJiri Pirko static void mlxsw_sp_port_module_info_fini(struct mlxsw_sp *mlxsw_sp)
21954a7f970fSJiri Pirko {
21964a7f970fSJiri Pirko kfree(mlxsw_sp->port_mapping);
21974a7f970fSJiri Pirko }
21984a7f970fSJiri Pirko
21997b39fa5bSJiri Pirko static int
mlxsw_sp_port_split_create(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_port_mapping * port_mapping,unsigned int count,const char * pmtdb_pl)220032ada69bSJiri Pirko mlxsw_sp_port_split_create(struct mlxsw_sp *mlxsw_sp,
22017b39fa5bSJiri Pirko struct mlxsw_sp_port_mapping *port_mapping,
220232ada69bSJiri Pirko unsigned int count, const char *pmtdb_pl)
2203be94535fSIdo Schimmel {
220435896d96SJiri Pirko struct mlxsw_sp_port_mapping split_port_mapping;
2205be94535fSIdo Schimmel int err, i;
2206be94535fSIdo Schimmel
220735896d96SJiri Pirko split_port_mapping = *port_mapping;
220835896d96SJiri Pirko split_port_mapping.width /= count;
2209be94535fSIdo Schimmel for (i = 0; i < count; i++) {
2210c934757dSAmit Cohen u16 s_local_port = mlxsw_reg_pmtdb_port_num_get(pmtdb_pl, i);
221132ada69bSJiri Pirko
221232ada69bSJiri Pirko if (!mlxsw_sp_local_port_valid(s_local_port))
221332ada69bSJiri Pirko continue;
221432ada69bSJiri Pirko
221532ada69bSJiri Pirko err = mlxsw_sp_port_create(mlxsw_sp, s_local_port,
221632ada69bSJiri Pirko true, &split_port_mapping);
2217be94535fSIdo Schimmel if (err)
2218be94535fSIdo Schimmel goto err_port_create;
221935896d96SJiri Pirko split_port_mapping.lane += split_port_mapping.width;
2220be94535fSIdo Schimmel }
2221be94535fSIdo Schimmel
2222be94535fSIdo Schimmel return 0;
2223be94535fSIdo Schimmel
2224be94535fSIdo Schimmel err_port_create:
222532ada69bSJiri Pirko for (i--; i >= 0; i--) {
2226c934757dSAmit Cohen u16 s_local_port = mlxsw_reg_pmtdb_port_num_get(pmtdb_pl, i);
222732ada69bSJiri Pirko
222832ada69bSJiri Pirko if (mlxsw_sp_port_created(mlxsw_sp, s_local_port))
222932ada69bSJiri Pirko mlxsw_sp_port_remove(mlxsw_sp, s_local_port);
223032ada69bSJiri Pirko }
2231be94535fSIdo Schimmel return err;
2232be94535fSIdo Schimmel }
2233be94535fSIdo Schimmel
mlxsw_sp_port_unsplit_create(struct mlxsw_sp * mlxsw_sp,unsigned int count,const char * pmtdb_pl)2234be94535fSIdo Schimmel static void mlxsw_sp_port_unsplit_create(struct mlxsw_sp *mlxsw_sp,
223532ada69bSJiri Pirko unsigned int count,
223632ada69bSJiri Pirko const char *pmtdb_pl)
2237be94535fSIdo Schimmel {
22384a7f970fSJiri Pirko struct mlxsw_sp_port_mapping *port_mapping;
2239be94535fSIdo Schimmel int i;
2240be94535fSIdo Schimmel
2241fbbeea31SJiri Pirko /* Go over original unsplit ports in the gap and recreate them. */
224232ada69bSJiri Pirko for (i = 0; i < count; i++) {
2243c934757dSAmit Cohen u16 local_port = mlxsw_reg_pmtdb_port_num_get(pmtdb_pl, i);
224432ada69bSJiri Pirko
2245d3ad2d88SJiri Pirko port_mapping = &mlxsw_sp->port_mapping[local_port];
2246d3ad2d88SJiri Pirko if (!port_mapping->width || !mlxsw_sp_local_port_valid(local_port))
2247bf4e9f24SIdo Schimmel continue;
224832ada69bSJiri Pirko mlxsw_sp_port_create(mlxsw_sp, local_port,
224932ada69bSJiri Pirko false, port_mapping);
2250be94535fSIdo Schimmel }
2251be94535fSIdo Schimmel }
2252be94535fSIdo Schimmel
22534340f42fSJiri Pirko static struct mlxsw_sp_port *
mlxsw_sp_port_get_by_local_port(struct mlxsw_sp * mlxsw_sp,u16 local_port)2254c934757dSAmit Cohen mlxsw_sp_port_get_by_local_port(struct mlxsw_sp *mlxsw_sp, u16 local_port)
22554340f42fSJiri Pirko {
22564340f42fSJiri Pirko if (mlxsw_sp->ports && mlxsw_sp->ports[local_port])
22574340f42fSJiri Pirko return mlxsw_sp->ports[local_port];
22584340f42fSJiri Pirko return NULL;
22594340f42fSJiri Pirko }
22604340f42fSJiri Pirko
mlxsw_sp_port_split(struct mlxsw_core * mlxsw_core,u16 local_port,unsigned int count,struct netlink_ext_ack * extack)2261c934757dSAmit Cohen static int mlxsw_sp_port_split(struct mlxsw_core *mlxsw_core, u16 local_port,
22623fcc773bSDavid Ahern unsigned int count,
22633fcc773bSDavid Ahern struct netlink_ext_ack *extack)
226418f1e70cSIdo Schimmel {
2265b2f10571SJiri Pirko struct mlxsw_sp *mlxsw_sp = mlxsw_core_driver_priv(mlxsw_core);
22667b39fa5bSJiri Pirko struct mlxsw_sp_port_mapping port_mapping;
226718f1e70cSIdo Schimmel struct mlxsw_sp_port *mlxsw_sp_port;
226832ada69bSJiri Pirko enum mlxsw_reg_pmtdb_status status;
226932ada69bSJiri Pirko char pmtdb_pl[MLXSW_REG_PMTDB_LEN];
227018f1e70cSIdo Schimmel int i;
227118f1e70cSIdo Schimmel int err;
227218f1e70cSIdo Schimmel
22734340f42fSJiri Pirko mlxsw_sp_port = mlxsw_sp_port_get_by_local_port(mlxsw_sp, local_port);
227418f1e70cSIdo Schimmel if (!mlxsw_sp_port) {
227518f1e70cSIdo Schimmel dev_err(mlxsw_sp->bus_info->dev, "Port number \"%d\" does not exist\n",
227618f1e70cSIdo Schimmel local_port);
22773fcc773bSDavid Ahern NL_SET_ERR_MSG_MOD(extack, "Port number does not exist");
227818f1e70cSIdo Schimmel return -EINVAL;
227918f1e70cSIdo Schimmel }
228018f1e70cSIdo Schimmel
228132ada69bSJiri Pirko if (mlxsw_sp_port->split) {
228232ada69bSJiri Pirko NL_SET_ERR_MSG_MOD(extack, "Port is already split");
228318f1e70cSIdo Schimmel return -EINVAL;
228418f1e70cSIdo Schimmel }
228518f1e70cSIdo Schimmel
22866445eef0SJiri Pirko mlxsw_reg_pmtdb_pack(pmtdb_pl, mlxsw_sp_port->mapping.slot_index,
22876445eef0SJiri Pirko mlxsw_sp_port->mapping.module,
228832ada69bSJiri Pirko mlxsw_sp_port->mapping.module_width / count,
228932ada69bSJiri Pirko count);
229032ada69bSJiri Pirko err = mlxsw_reg_query(mlxsw_core, MLXSW_REG(pmtdb), pmtdb_pl);
229132ada69bSJiri Pirko if (err) {
229232ada69bSJiri Pirko NL_SET_ERR_MSG_MOD(extack, "Failed to query split info");
229332ada69bSJiri Pirko return err;
2294d0846ce9SJiri Pirko }
2295d0846ce9SJiri Pirko
229632ada69bSJiri Pirko status = mlxsw_reg_pmtdb_status_get(pmtdb_pl);
229732ada69bSJiri Pirko if (status != MLXSW_REG_PMTDB_STATUS_SUCCESS) {
229832ada69bSJiri Pirko NL_SET_ERR_MSG_MOD(extack, "Unsupported split configuration");
229918f1e70cSIdo Schimmel return -EINVAL;
230018f1e70cSIdo Schimmel }
230118f1e70cSIdo Schimmel
23027b39fa5bSJiri Pirko port_mapping = mlxsw_sp_port->mapping;
23037b39fa5bSJiri Pirko
230432ada69bSJiri Pirko for (i = 0; i < count; i++) {
2305c934757dSAmit Cohen u16 s_local_port = mlxsw_reg_pmtdb_port_num_get(pmtdb_pl, i);
230618f1e70cSIdo Schimmel
230732ada69bSJiri Pirko if (mlxsw_sp_port_created(mlxsw_sp, s_local_port))
230832ada69bSJiri Pirko mlxsw_sp_port_remove(mlxsw_sp, s_local_port);
230932ada69bSJiri Pirko }
231032ada69bSJiri Pirko
231132ada69bSJiri Pirko err = mlxsw_sp_port_split_create(mlxsw_sp, &port_mapping,
231232ada69bSJiri Pirko count, pmtdb_pl);
231318f1e70cSIdo Schimmel if (err) {
2314be94535fSIdo Schimmel dev_err(mlxsw_sp->bus_info->dev, "Failed to create split ports\n");
2315be94535fSIdo Schimmel goto err_port_split_create;
231618f1e70cSIdo Schimmel }
231718f1e70cSIdo Schimmel
231818f1e70cSIdo Schimmel return 0;
231918f1e70cSIdo Schimmel
2320be94535fSIdo Schimmel err_port_split_create:
232132ada69bSJiri Pirko mlxsw_sp_port_unsplit_create(mlxsw_sp, count, pmtdb_pl);
2322b0ec003eSJiri Pirko
232318f1e70cSIdo Schimmel return err;
232418f1e70cSIdo Schimmel }
232518f1e70cSIdo Schimmel
mlxsw_sp_port_unsplit(struct mlxsw_core * mlxsw_core,u16 local_port,struct netlink_ext_ack * extack)2326c934757dSAmit Cohen static int mlxsw_sp_port_unsplit(struct mlxsw_core *mlxsw_core, u16 local_port,
23273fcc773bSDavid Ahern struct netlink_ext_ack *extack)
232818f1e70cSIdo Schimmel {
2329b2f10571SJiri Pirko struct mlxsw_sp *mlxsw_sp = mlxsw_core_driver_priv(mlxsw_core);
233018f1e70cSIdo Schimmel struct mlxsw_sp_port *mlxsw_sp_port;
233132ada69bSJiri Pirko char pmtdb_pl[MLXSW_REG_PMTDB_LEN];
233218f1e70cSIdo Schimmel unsigned int count;
233318f1e70cSIdo Schimmel int i;
233432ada69bSJiri Pirko int err;
233518f1e70cSIdo Schimmel
23364340f42fSJiri Pirko mlxsw_sp_port = mlxsw_sp_port_get_by_local_port(mlxsw_sp, local_port);
233718f1e70cSIdo Schimmel if (!mlxsw_sp_port) {
233818f1e70cSIdo Schimmel dev_err(mlxsw_sp->bus_info->dev, "Port number \"%d\" does not exist\n",
233918f1e70cSIdo Schimmel local_port);
23403fcc773bSDavid Ahern NL_SET_ERR_MSG_MOD(extack, "Port number does not exist");
234118f1e70cSIdo Schimmel return -EINVAL;
234218f1e70cSIdo Schimmel }
234318f1e70cSIdo Schimmel
234418f1e70cSIdo Schimmel if (!mlxsw_sp_port->split) {
23453fcc773bSDavid Ahern NL_SET_ERR_MSG_MOD(extack, "Port was not split");
234618f1e70cSIdo Schimmel return -EINVAL;
234718f1e70cSIdo Schimmel }
234818f1e70cSIdo Schimmel
234932ada69bSJiri Pirko count = mlxsw_sp_port->mapping.module_width /
235032ada69bSJiri Pirko mlxsw_sp_port->mapping.width;
235132ada69bSJiri Pirko
23526445eef0SJiri Pirko mlxsw_reg_pmtdb_pack(pmtdb_pl, mlxsw_sp_port->mapping.slot_index,
23536445eef0SJiri Pirko mlxsw_sp_port->mapping.module,
235432ada69bSJiri Pirko mlxsw_sp_port->mapping.module_width / count,
235532ada69bSJiri Pirko count);
235632ada69bSJiri Pirko err = mlxsw_reg_query(mlxsw_core, MLXSW_REG(pmtdb), pmtdb_pl);
235732ada69bSJiri Pirko if (err) {
235832ada69bSJiri Pirko NL_SET_ERR_MSG_MOD(extack, "Failed to query split info");
235932ada69bSJiri Pirko return err;
236025911e1bSJiri Pirko }
236125911e1bSJiri Pirko
236232ada69bSJiri Pirko for (i = 0; i < count; i++) {
2363c934757dSAmit Cohen u16 s_local_port = mlxsw_reg_pmtdb_port_num_get(pmtdb_pl, i);
236418f1e70cSIdo Schimmel
236532ada69bSJiri Pirko if (mlxsw_sp_port_created(mlxsw_sp, s_local_port))
236632ada69bSJiri Pirko mlxsw_sp_port_remove(mlxsw_sp, s_local_port);
2367d0846ce9SJiri Pirko }
2368fd321c6cSShalom Toledo
236932ada69bSJiri Pirko mlxsw_sp_port_unsplit_create(mlxsw_sp, count, pmtdb_pl);
237018f1e70cSIdo Schimmel
237118f1e70cSIdo Schimmel return 0;
237218f1e70cSIdo Schimmel }
237318f1e70cSIdo Schimmel
2374ca7609ffSPetr Machata static void
mlxsw_sp_port_down_wipe_counters(struct mlxsw_sp_port * mlxsw_sp_port)2375ca7609ffSPetr Machata mlxsw_sp_port_down_wipe_counters(struct mlxsw_sp_port *mlxsw_sp_port)
2376ca7609ffSPetr Machata {
2377ca7609ffSPetr Machata int i;
2378ca7609ffSPetr Machata
2379ca7609ffSPetr Machata for (i = 0; i < TC_MAX_QUEUE; i++)
2380ca7609ffSPetr Machata mlxsw_sp_port->periodic_hw_stats.xstats.backlog[i] = 0;
2381ca7609ffSPetr Machata }
2382ca7609ffSPetr Machata
mlxsw_sp_pude_event_func(const struct mlxsw_reg_info * reg,char * pude_pl,void * priv)238356ade8feSJiri Pirko static void mlxsw_sp_pude_event_func(const struct mlxsw_reg_info *reg,
238456ade8feSJiri Pirko char *pude_pl, void *priv)
238556ade8feSJiri Pirko {
238656ade8feSJiri Pirko struct mlxsw_sp *mlxsw_sp = priv;
238756ade8feSJiri Pirko struct mlxsw_sp_port *mlxsw_sp_port;
238856ade8feSJiri Pirko enum mlxsw_reg_pude_oper_status status;
2389c934757dSAmit Cohen u16 local_port;
239056ade8feSJiri Pirko
239156ade8feSJiri Pirko local_port = mlxsw_reg_pude_local_port_get(pude_pl);
2392837ec05cSDanielle Ratson
2393bcdfd615SAmit Cohen if (WARN_ON_ONCE(!mlxsw_sp_local_port_is_valid(mlxsw_sp, local_port)))
2394837ec05cSDanielle Ratson return;
239556ade8feSJiri Pirko mlxsw_sp_port = mlxsw_sp->ports[local_port];
2396bbf2a475SIdo Schimmel if (!mlxsw_sp_port)
239756ade8feSJiri Pirko return;
239856ade8feSJiri Pirko
239956ade8feSJiri Pirko status = mlxsw_reg_pude_oper_status_get(pude_pl);
240056ade8feSJiri Pirko if (status == MLXSW_PORT_OPER_STATUS_UP) {
240156ade8feSJiri Pirko netdev_info(mlxsw_sp_port->dev, "link up\n");
240256ade8feSJiri Pirko netif_carrier_on(mlxsw_sp_port->dev);
24035fc17338SShalom Toledo mlxsw_core_schedule_dw(&mlxsw_sp_port->ptp.shaper_dw, 0);
240456ade8feSJiri Pirko } else {
240556ade8feSJiri Pirko netdev_info(mlxsw_sp_port->dev, "link down\n");
240656ade8feSJiri Pirko netif_carrier_off(mlxsw_sp_port->dev);
2407ca7609ffSPetr Machata mlxsw_sp_port_down_wipe_counters(mlxsw_sp_port);
240856ade8feSJiri Pirko }
240956ade8feSJiri Pirko }
241056ade8feSJiri Pirko
mlxsw_sp1_ptp_fifo_event_func(struct mlxsw_sp * mlxsw_sp,char * mtpptr_pl,bool ingress)2411d92e4e6eSPetr Machata static void mlxsw_sp1_ptp_fifo_event_func(struct mlxsw_sp *mlxsw_sp,
2412d92e4e6eSPetr Machata char *mtpptr_pl, bool ingress)
2413d92e4e6eSPetr Machata {
2414c934757dSAmit Cohen u16 local_port;
2415d92e4e6eSPetr Machata u8 num_rec;
2416d92e4e6eSPetr Machata int i;
2417d92e4e6eSPetr Machata
2418d92e4e6eSPetr Machata local_port = mlxsw_reg_mtpptr_local_port_get(mtpptr_pl);
2419d92e4e6eSPetr Machata num_rec = mlxsw_reg_mtpptr_num_rec_get(mtpptr_pl);
2420d92e4e6eSPetr Machata for (i = 0; i < num_rec; i++) {
2421d92e4e6eSPetr Machata u8 domain_number;
2422d92e4e6eSPetr Machata u8 message_type;
2423d92e4e6eSPetr Machata u16 sequence_id;
2424d92e4e6eSPetr Machata u64 timestamp;
2425d92e4e6eSPetr Machata
2426d92e4e6eSPetr Machata mlxsw_reg_mtpptr_unpack(mtpptr_pl, i, &message_type,
2427d92e4e6eSPetr Machata &domain_number, &sequence_id,
2428d92e4e6eSPetr Machata ×tamp);
2429d92e4e6eSPetr Machata mlxsw_sp1_ptp_got_timestamp(mlxsw_sp, ingress, local_port,
2430d92e4e6eSPetr Machata message_type, domain_number,
2431d92e4e6eSPetr Machata sequence_id, timestamp);
2432d92e4e6eSPetr Machata }
2433d92e4e6eSPetr Machata }
2434d92e4e6eSPetr Machata
mlxsw_sp1_ptp_ing_fifo_event_func(const struct mlxsw_reg_info * reg,char * mtpptr_pl,void * priv)2435d92e4e6eSPetr Machata static void mlxsw_sp1_ptp_ing_fifo_event_func(const struct mlxsw_reg_info *reg,
2436d92e4e6eSPetr Machata char *mtpptr_pl, void *priv)
2437d92e4e6eSPetr Machata {
2438d92e4e6eSPetr Machata struct mlxsw_sp *mlxsw_sp = priv;
2439d92e4e6eSPetr Machata
2440d92e4e6eSPetr Machata mlxsw_sp1_ptp_fifo_event_func(mlxsw_sp, mtpptr_pl, true);
2441d92e4e6eSPetr Machata }
2442d92e4e6eSPetr Machata
mlxsw_sp1_ptp_egr_fifo_event_func(const struct mlxsw_reg_info * reg,char * mtpptr_pl,void * priv)2443d92e4e6eSPetr Machata static void mlxsw_sp1_ptp_egr_fifo_event_func(const struct mlxsw_reg_info *reg,
2444d92e4e6eSPetr Machata char *mtpptr_pl, void *priv)
2445d92e4e6eSPetr Machata {
2446d92e4e6eSPetr Machata struct mlxsw_sp *mlxsw_sp = priv;
2447d92e4e6eSPetr Machata
2448d92e4e6eSPetr Machata mlxsw_sp1_ptp_fifo_event_func(mlxsw_sp, mtpptr_pl, false);
2449d92e4e6eSPetr Machata }
2450d92e4e6eSPetr Machata
mlxsw_sp_rx_listener_no_mark_func(struct sk_buff * skb,u16 local_port,void * priv)2451aed4b572SPetr Machata void mlxsw_sp_rx_listener_no_mark_func(struct sk_buff *skb,
2452c934757dSAmit Cohen u16 local_port, void *priv)
245356ade8feSJiri Pirko {
245456ade8feSJiri Pirko struct mlxsw_sp *mlxsw_sp = priv;
245556ade8feSJiri Pirko struct mlxsw_sp_port *mlxsw_sp_port = mlxsw_sp->ports[local_port];
245656ade8feSJiri Pirko struct mlxsw_sp_port_pcpu_stats *pcpu_stats;
245756ade8feSJiri Pirko
245856ade8feSJiri Pirko if (unlikely(!mlxsw_sp_port)) {
245956ade8feSJiri Pirko dev_warn_ratelimited(mlxsw_sp->bus_info->dev, "Port %d: skb received for non-existent port\n",
246056ade8feSJiri Pirko local_port);
246156ade8feSJiri Pirko return;
246256ade8feSJiri Pirko }
246356ade8feSJiri Pirko
246456ade8feSJiri Pirko skb->dev = mlxsw_sp_port->dev;
246556ade8feSJiri Pirko
246656ade8feSJiri Pirko pcpu_stats = this_cpu_ptr(mlxsw_sp_port->pcpu_stats);
246756ade8feSJiri Pirko u64_stats_update_begin(&pcpu_stats->syncp);
246856ade8feSJiri Pirko pcpu_stats->rx_packets++;
246956ade8feSJiri Pirko pcpu_stats->rx_bytes += skb->len;
247056ade8feSJiri Pirko u64_stats_update_end(&pcpu_stats->syncp);
247156ade8feSJiri Pirko
247256ade8feSJiri Pirko skb->protocol = eth_type_trans(skb, skb->dev);
247356ade8feSJiri Pirko netif_receive_skb(skb);
247456ade8feSJiri Pirko }
247556ade8feSJiri Pirko
mlxsw_sp_rx_listener_mark_func(struct sk_buff * skb,u16 local_port,void * priv)2476c934757dSAmit Cohen static void mlxsw_sp_rx_listener_mark_func(struct sk_buff *skb, u16 local_port,
24771c6c6d22SIdo Schimmel void *priv)
24781c6c6d22SIdo Schimmel {
24791c6c6d22SIdo Schimmel skb->offload_fwd_mark = 1;
248014eeda99SNogah Frankel return mlxsw_sp_rx_listener_no_mark_func(skb, local_port, priv);
24811c6c6d22SIdo Schimmel }
24821c6c6d22SIdo Schimmel
mlxsw_sp_rx_listener_l3_mark_func(struct sk_buff * skb,u16 local_port,void * priv)2483875e8939SIdo Schimmel static void mlxsw_sp_rx_listener_l3_mark_func(struct sk_buff *skb,
2484c934757dSAmit Cohen u16 local_port, void *priv)
2485a0040c8cSYotam Gigi {
2486875e8939SIdo Schimmel skb->offload_l3_fwd_mark = 1;
2487a0040c8cSYotam Gigi skb->offload_fwd_mark = 1;
2488a0040c8cSYotam Gigi return mlxsw_sp_rx_listener_no_mark_func(skb, local_port, priv);
2489a0040c8cSYotam Gigi }
2490a0040c8cSYotam Gigi
mlxsw_sp_ptp_receive(struct mlxsw_sp * mlxsw_sp,struct sk_buff * skb,u16 local_port)249188e27749SIdo Schimmel void mlxsw_sp_ptp_receive(struct mlxsw_sp *mlxsw_sp, struct sk_buff *skb,
2492c934757dSAmit Cohen u16 local_port)
249398d0f7b9SYotam Gigi {
249488e27749SIdo Schimmel mlxsw_sp->ptp_ops->receive(mlxsw_sp, skb, local_port);
249588e27749SIdo Schimmel }
249688e27749SIdo Schimmel
2497117b0dadSNogah Frankel #define MLXSW_SP_RXL_NO_MARK(_trap_id, _action, _trap_group, _is_ctrl) \
249814eeda99SNogah Frankel MLXSW_RXL(mlxsw_sp_rx_listener_no_mark_func, _trap_id, _action, \
2499117b0dadSNogah Frankel _is_ctrl, SP_##_trap_group, DISCARD)
250093393b33SIdo Schimmel
2501117b0dadSNogah Frankel #define MLXSW_SP_RXL_MARK(_trap_id, _action, _trap_group, _is_ctrl) \
250214eeda99SNogah Frankel MLXSW_RXL(mlxsw_sp_rx_listener_mark_func, _trap_id, _action, \
2503117b0dadSNogah Frankel _is_ctrl, SP_##_trap_group, DISCARD)
2504117b0dadSNogah Frankel
2505875e8939SIdo Schimmel #define MLXSW_SP_RXL_L3_MARK(_trap_id, _action, _trap_group, _is_ctrl) \
2506875e8939SIdo Schimmel MLXSW_RXL(mlxsw_sp_rx_listener_l3_mark_func, _trap_id, _action, \
2507a0040c8cSYotam Gigi _is_ctrl, SP_##_trap_group, DISCARD)
2508a0040c8cSYotam Gigi
2509117b0dadSNogah Frankel #define MLXSW_SP_EVENTL(_func, _trap_id) \
2510117b0dadSNogah Frankel MLXSW_EVENTL(_func, _trap_id, SP_EVENT)
251114eeda99SNogah Frankel
25124544913eSNogah Frankel static const struct mlxsw_listener mlxsw_sp_listener[] = {
25134544913eSNogah Frankel /* Events */
2514117b0dadSNogah Frankel MLXSW_SP_EVENTL(mlxsw_sp_pude_event_func, PUDE),
2515ee4a60d8SNogah Frankel /* L2 traps */
2516d322309dSIdo Schimmel MLXSW_SP_RXL_NO_MARK(FID_MISS, TRAP_TO_CPU, FID_MISS, false),
251793393b33SIdo Schimmel /* L3 traps */
25188d54814eSArkadi Sharshevsky MLXSW_SP_RXL_MARK(IPV6_UNSPECIFIED_ADDRESS, TRAP_TO_CPU, ROUTER_EXP,
25198d54814eSArkadi Sharshevsky false),
2520dacc4e3aSIdo Schimmel MLXSW_SP_RXL_MARK(IPV6_LINK_LOCAL_SRC, TRAP_TO_CPU, ROUTER_EXP, false),
25218d54814eSArkadi Sharshevsky MLXSW_SP_RXL_MARK(IPV6_MC_LINK_LOCAL_DEST, TRAP_TO_CPU, ROUTER_EXP,
25228d54814eSArkadi Sharshevsky false),
252362b0fb09SAmit Cohen MLXSW_SP_RXL_NO_MARK(DISCARD_ING_ROUTER_SIP_CLASS_E, FORWARD,
252462b0fb09SAmit Cohen ROUTER_EXP, false),
2525359ec566SAmit Cohen MLXSW_SP_RXL_NO_MARK(DISCARD_ING_ROUTER_MC_DMAC, FORWARD,
2526359ec566SAmit Cohen ROUTER_EXP, false),
2527e317b0f7SAmit Cohen MLXSW_SP_RXL_NO_MARK(DISCARD_ING_ROUTER_SIP_DIP, FORWARD,
2528e317b0f7SAmit Cohen ROUTER_EXP, false),
2529ca360db4SAmit Cohen MLXSW_SP_RXL_NO_MARK(DISCARD_ING_ROUTER_DIP_LINK_LOCAL, FORWARD,
2530ca360db4SAmit Cohen ROUTER_EXP, false),
2531b48cfc80SYotam Gigi /* Multicast Router Traps */
2532b48cfc80SYotam Gigi MLXSW_SP_RXL_MARK(ACL1, TRAP_TO_CPU, MULTICAST, false),
2533875e8939SIdo Schimmel MLXSW_SP_RXL_L3_MARK(ACL2, TRAP_TO_CPU, MULTICAST, false),
2534b02597d5SIdo Schimmel /* NVE traps */
253532446438SIdo Schimmel MLXSW_SP_RXL_MARK(NVE_ENCAP_ARP, TRAP_TO_CPU, NEIGH_DISCOVERY, false),
253656ade8feSJiri Pirko };
253756ade8feSJiri Pirko
2538dadbc6bcSPetr Machata static const struct mlxsw_listener mlxsw_sp1_listener[] = {
2539d92e4e6eSPetr Machata /* Events */
2540d92e4e6eSPetr Machata MLXSW_EVENTL(mlxsw_sp1_ptp_egr_fifo_event_func, PTP_EGR_FIFO, SP_PTP0),
2541d92e4e6eSPetr Machata MLXSW_EVENTL(mlxsw_sp1_ptp_ing_fifo_event_func, PTP_ING_FIFO, SP_PTP0),
2542dadbc6bcSPetr Machata };
2543dadbc6bcSPetr Machata
2544b0ec003eSJiri Pirko static const struct mlxsw_listener mlxsw_sp2_listener[] = {
2545b0ec003eSJiri Pirko /* Events */
2546b0ec003eSJiri Pirko MLXSW_SP_EVENTL(mlxsw_sp_port_mapping_listener_func, PMLPE),
2547b0ec003eSJiri Pirko };
2548b0ec003eSJiri Pirko
mlxsw_sp_cpu_policers_set(struct mlxsw_core * mlxsw_core)25499148e7cfSNogah Frankel static int mlxsw_sp_cpu_policers_set(struct mlxsw_core *mlxsw_core)
25509148e7cfSNogah Frankel {
255103484e49SIdo Schimmel struct mlxsw_sp *mlxsw_sp = mlxsw_core_driver_priv(mlxsw_core);
25529148e7cfSNogah Frankel char qpcr_pl[MLXSW_REG_QPCR_LEN];
25539148e7cfSNogah Frankel enum mlxsw_reg_qpcr_ir_units ir_units;
25549148e7cfSNogah Frankel int max_cpu_policers;
25559148e7cfSNogah Frankel bool is_bytes;
25569148e7cfSNogah Frankel u8 burst_size;
25579148e7cfSNogah Frankel u32 rate;
25589148e7cfSNogah Frankel int i, err;
25599148e7cfSNogah Frankel
25609148e7cfSNogah Frankel if (!MLXSW_CORE_RES_VALID(mlxsw_core, MAX_CPU_POLICERS))
25619148e7cfSNogah Frankel return -EIO;
25629148e7cfSNogah Frankel
25639148e7cfSNogah Frankel max_cpu_policers = MLXSW_CORE_RES_GET(mlxsw_core, MAX_CPU_POLICERS);
25649148e7cfSNogah Frankel
25659148e7cfSNogah Frankel ir_units = MLXSW_REG_QPCR_IR_UNITS_M;
25669148e7cfSNogah Frankel for (i = 0; i < max_cpu_policers; i++) {
25679148e7cfSNogah Frankel is_bytes = false;
25689148e7cfSNogah Frankel switch (i) {
25699148e7cfSNogah Frankel case MLXSW_REG_HTGT_TRAP_GROUP_SP_ROUTER_EXP:
2570b48cfc80SYotam Gigi case MLXSW_REG_HTGT_TRAP_GROUP_SP_MULTICAST:
2571d322309dSIdo Schimmel case MLXSW_REG_HTGT_TRAP_GROUP_SP_FID_MISS:
257231ef5b0eSShalom Toledo rate = 1024;
257331ef5b0eSShalom Toledo burst_size = 7;
25749148e7cfSNogah Frankel break;
25759148e7cfSNogah Frankel default:
25769148e7cfSNogah Frankel continue;
25779148e7cfSNogah Frankel }
25789148e7cfSNogah Frankel
257903484e49SIdo Schimmel __set_bit(i, mlxsw_sp->trap->policers_usage);
25809148e7cfSNogah Frankel mlxsw_reg_qpcr_pack(qpcr_pl, i, ir_units, is_bytes, rate,
25819148e7cfSNogah Frankel burst_size);
25829148e7cfSNogah Frankel err = mlxsw_reg_write(mlxsw_core, MLXSW_REG(qpcr), qpcr_pl);
25839148e7cfSNogah Frankel if (err)
25849148e7cfSNogah Frankel return err;
25859148e7cfSNogah Frankel }
25869148e7cfSNogah Frankel
25879148e7cfSNogah Frankel return 0;
25889148e7cfSNogah Frankel }
25899148e7cfSNogah Frankel
mlxsw_sp_trap_groups_set(struct mlxsw_core * mlxsw_core)2590579c82e4SNogah Frankel static int mlxsw_sp_trap_groups_set(struct mlxsw_core *mlxsw_core)
259156ade8feSJiri Pirko {
259256ade8feSJiri Pirko char htgt_pl[MLXSW_REG_HTGT_LEN];
2593117b0dadSNogah Frankel enum mlxsw_reg_htgt_trap_group i;
25949148e7cfSNogah Frankel int max_cpu_policers;
2595579c82e4SNogah Frankel int max_trap_groups;
2596579c82e4SNogah Frankel u8 priority, tc;
25979148e7cfSNogah Frankel u16 policer_id;
2598117b0dadSNogah Frankel int err;
2599579c82e4SNogah Frankel
2600579c82e4SNogah Frankel if (!MLXSW_CORE_RES_VALID(mlxsw_core, MAX_TRAP_GROUPS))
2601579c82e4SNogah Frankel return -EIO;
2602579c82e4SNogah Frankel
2603579c82e4SNogah Frankel max_trap_groups = MLXSW_CORE_RES_GET(mlxsw_core, MAX_TRAP_GROUPS);
26049148e7cfSNogah Frankel max_cpu_policers = MLXSW_CORE_RES_GET(mlxsw_core, MAX_CPU_POLICERS);
2605579c82e4SNogah Frankel
2606579c82e4SNogah Frankel for (i = 0; i < max_trap_groups; i++) {
26079148e7cfSNogah Frankel policer_id = i;
2608579c82e4SNogah Frankel switch (i) {
2609117b0dadSNogah Frankel case MLXSW_REG_HTGT_TRAP_GROUP_SP_ROUTER_EXP:
2610b48cfc80SYotam Gigi case MLXSW_REG_HTGT_TRAP_GROUP_SP_MULTICAST:
2611d322309dSIdo Schimmel case MLXSW_REG_HTGT_TRAP_GROUP_SP_FID_MISS:
2612117b0dadSNogah Frankel priority = 1;
2613117b0dadSNogah Frankel tc = 1;
2614117b0dadSNogah Frankel break;
2615117b0dadSNogah Frankel case MLXSW_REG_HTGT_TRAP_GROUP_SP_EVENT:
2616579c82e4SNogah Frankel priority = MLXSW_REG_HTGT_DEFAULT_PRIORITY;
2617579c82e4SNogah Frankel tc = MLXSW_REG_HTGT_DEFAULT_TC;
26189148e7cfSNogah Frankel policer_id = MLXSW_REG_HTGT_INVALID_POLICER;
2619579c82e4SNogah Frankel break;
2620579c82e4SNogah Frankel default:
2621579c82e4SNogah Frankel continue;
2622579c82e4SNogah Frankel }
2623117b0dadSNogah Frankel
26249148e7cfSNogah Frankel if (max_cpu_policers <= policer_id &&
26259148e7cfSNogah Frankel policer_id != MLXSW_REG_HTGT_INVALID_POLICER)
26269148e7cfSNogah Frankel return -EIO;
26279148e7cfSNogah Frankel
26289148e7cfSNogah Frankel mlxsw_reg_htgt_pack(htgt_pl, i, policer_id, priority, tc);
2629579c82e4SNogah Frankel err = mlxsw_reg_write(mlxsw_core, MLXSW_REG(htgt), htgt_pl);
2630579c82e4SNogah Frankel if (err)
2631579c82e4SNogah Frankel return err;
2632579c82e4SNogah Frankel }
2633579c82e4SNogah Frankel
2634579c82e4SNogah Frankel return 0;
2635579c82e4SNogah Frankel }
2636579c82e4SNogah Frankel
mlxsw_sp_traps_init(struct mlxsw_sp * mlxsw_sp)26374b6b91edSPetr Machata static int mlxsw_sp_traps_init(struct mlxsw_sp *mlxsw_sp)
26384b6b91edSPetr Machata {
263903484e49SIdo Schimmel struct mlxsw_sp_trap *trap;
264003484e49SIdo Schimmel u64 max_policers;
26414b6b91edSPetr Machata int err;
26424b6b91edSPetr Machata
264303484e49SIdo Schimmel if (!MLXSW_CORE_RES_VALID(mlxsw_sp->core, MAX_CPU_POLICERS))
264403484e49SIdo Schimmel return -EIO;
264503484e49SIdo Schimmel max_policers = MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_CPU_POLICERS);
264603484e49SIdo Schimmel trap = kzalloc(struct_size(trap, policers_usage,
264703484e49SIdo Schimmel BITS_TO_LONGS(max_policers)), GFP_KERNEL);
264803484e49SIdo Schimmel if (!trap)
264903484e49SIdo Schimmel return -ENOMEM;
265003484e49SIdo Schimmel trap->max_policers = max_policers;
265103484e49SIdo Schimmel mlxsw_sp->trap = trap;
265203484e49SIdo Schimmel
26534b6b91edSPetr Machata err = mlxsw_sp_cpu_policers_set(mlxsw_sp->core);
26544b6b91edSPetr Machata if (err)
265503484e49SIdo Schimmel goto err_cpu_policers_set;
26564b6b91edSPetr Machata
26574b6b91edSPetr Machata err = mlxsw_sp_trap_groups_set(mlxsw_sp->core);
26584b6b91edSPetr Machata if (err)
265903484e49SIdo Schimmel goto err_trap_groups_set;
26604b6b91edSPetr Machata
2661981f1d18SJiri Pirko err = mlxsw_core_traps_register(mlxsw_sp->core, mlxsw_sp_listener,
2662981f1d18SJiri Pirko ARRAY_SIZE(mlxsw_sp_listener),
2663981f1d18SJiri Pirko mlxsw_sp);
2664dadbc6bcSPetr Machata if (err)
266503484e49SIdo Schimmel goto err_traps_register;
2666dadbc6bcSPetr Machata
2667981f1d18SJiri Pirko err = mlxsw_core_traps_register(mlxsw_sp->core, mlxsw_sp->listeners,
2668981f1d18SJiri Pirko mlxsw_sp->listeners_count, mlxsw_sp);
2669dadbc6bcSPetr Machata if (err)
2670dadbc6bcSPetr Machata goto err_extra_traps_init;
2671dadbc6bcSPetr Machata
2672dadbc6bcSPetr Machata return 0;
2673dadbc6bcSPetr Machata
2674dadbc6bcSPetr Machata err_extra_traps_init:
2675981f1d18SJiri Pirko mlxsw_core_traps_unregister(mlxsw_sp->core, mlxsw_sp_listener,
2676981f1d18SJiri Pirko ARRAY_SIZE(mlxsw_sp_listener),
2677981f1d18SJiri Pirko mlxsw_sp);
267803484e49SIdo Schimmel err_traps_register:
267903484e49SIdo Schimmel err_trap_groups_set:
268003484e49SIdo Schimmel err_cpu_policers_set:
268103484e49SIdo Schimmel kfree(trap);
2682dadbc6bcSPetr Machata return err;
26834b6b91edSPetr Machata }
26844b6b91edSPetr Machata
mlxsw_sp_traps_fini(struct mlxsw_sp * mlxsw_sp)26854b6b91edSPetr Machata static void mlxsw_sp_traps_fini(struct mlxsw_sp *mlxsw_sp)
26864b6b91edSPetr Machata {
2687981f1d18SJiri Pirko mlxsw_core_traps_unregister(mlxsw_sp->core, mlxsw_sp->listeners,
2688981f1d18SJiri Pirko mlxsw_sp->listeners_count,
2689981f1d18SJiri Pirko mlxsw_sp);
2690981f1d18SJiri Pirko mlxsw_core_traps_unregister(mlxsw_sp->core, mlxsw_sp_listener,
2691981f1d18SJiri Pirko ARRAY_SIZE(mlxsw_sp_listener), mlxsw_sp);
269203484e49SIdo Schimmel kfree(mlxsw_sp->trap);
26934b6b91edSPetr Machata }
26944b6b91edSPetr Machata
2695ee02c269SIdo Schimmel #define MLXSW_SP_LAG_SEED_INIT 0xcafecafe
2696ee02c269SIdo Schimmel
mlxsw_sp_lag_init(struct mlxsw_sp * mlxsw_sp)26970d65fc13SJiri Pirko static int mlxsw_sp_lag_init(struct mlxsw_sp *mlxsw_sp)
26980d65fc13SJiri Pirko {
26990d65fc13SJiri Pirko char slcr_pl[MLXSW_REG_SLCR_LEN];
2700cf735d4cSAmit Cohen u16 max_lag;
2701beda7f72SIdo Schimmel u32 seed;
2702ce0bd2b0SNogah Frankel int err;
27030d65fc13SJiri Pirko
2704ee02c269SIdo Schimmel seed = jhash(mlxsw_sp->base_mac, sizeof(mlxsw_sp->base_mac),
2705ee02c269SIdo Schimmel MLXSW_SP_LAG_SEED_INIT);
27060d65fc13SJiri Pirko mlxsw_reg_slcr_pack(slcr_pl, MLXSW_REG_SLCR_LAG_HASH_SMAC |
27070d65fc13SJiri Pirko MLXSW_REG_SLCR_LAG_HASH_DMAC |
27080d65fc13SJiri Pirko MLXSW_REG_SLCR_LAG_HASH_ETHERTYPE |
27090d65fc13SJiri Pirko MLXSW_REG_SLCR_LAG_HASH_VLANID |
27100d65fc13SJiri Pirko MLXSW_REG_SLCR_LAG_HASH_SIP |
27110d65fc13SJiri Pirko MLXSW_REG_SLCR_LAG_HASH_DIP |
27120d65fc13SJiri Pirko MLXSW_REG_SLCR_LAG_HASH_SPORT |
27130d65fc13SJiri Pirko MLXSW_REG_SLCR_LAG_HASH_DPORT |
2714beda7f72SIdo Schimmel MLXSW_REG_SLCR_LAG_HASH_IPPROTO, seed);
2715ce0bd2b0SNogah Frankel err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(slcr), slcr_pl);
2716ce0bd2b0SNogah Frankel if (err)
2717ce0bd2b0SNogah Frankel return err;
2718ce0bd2b0SNogah Frankel
2719cf735d4cSAmit Cohen err = mlxsw_core_max_lag(mlxsw_sp->core, &max_lag);
2720cf735d4cSAmit Cohen if (err)
2721cf735d4cSAmit Cohen return err;
2722cf735d4cSAmit Cohen
2723cf735d4cSAmit Cohen if (!MLXSW_CORE_RES_VALID(mlxsw_sp->core, MAX_LAG_MEMBERS))
2724ce0bd2b0SNogah Frankel return -EIO;
2725ce0bd2b0SNogah Frankel
2726cf735d4cSAmit Cohen mlxsw_sp->lags = kcalloc(max_lag, sizeof(struct mlxsw_sp_upper),
2727ce0bd2b0SNogah Frankel GFP_KERNEL);
2728ce0bd2b0SNogah Frankel if (!mlxsw_sp->lags)
2729ce0bd2b0SNogah Frankel return -ENOMEM;
2730ce0bd2b0SNogah Frankel
2731ce0bd2b0SNogah Frankel return 0;
2732ce0bd2b0SNogah Frankel }
2733ce0bd2b0SNogah Frankel
mlxsw_sp_lag_fini(struct mlxsw_sp * mlxsw_sp)2734ce0bd2b0SNogah Frankel static void mlxsw_sp_lag_fini(struct mlxsw_sp *mlxsw_sp)
2735ce0bd2b0SNogah Frankel {
2736ce0bd2b0SNogah Frankel kfree(mlxsw_sp->lags);
27370d65fc13SJiri Pirko }
27380d65fc13SJiri Pirko
2739412cd2adSShalom Toledo static const struct mlxsw_sp_ptp_ops mlxsw_sp1_ptp_ops = {
2740412cd2adSShalom Toledo .clock_init = mlxsw_sp1_ptp_clock_init,
2741412cd2adSShalom Toledo .clock_fini = mlxsw_sp1_ptp_clock_fini,
2742810256ceSPetr Machata .init = mlxsw_sp1_ptp_init,
2743810256ceSPetr Machata .fini = mlxsw_sp1_ptp_fini,
2744aed4b572SPetr Machata .receive = mlxsw_sp1_ptp_receive,
27450714256cSPetr Machata .transmitted = mlxsw_sp1_ptp_transmitted,
274687486427SPetr Machata .hwtstamp_get = mlxsw_sp1_ptp_hwtstamp_get,
274787486427SPetr Machata .hwtstamp_set = mlxsw_sp1_ptp_hwtstamp_set,
27485fc17338SShalom Toledo .shaper_work = mlxsw_sp1_ptp_shaper_work,
274987ee07f8SPetr Machata .get_ts_info = mlxsw_sp1_ptp_get_ts_info,
2750dc4f3eb0SPetr Machata .get_stats_count = mlxsw_sp1_get_stats_count,
2751dc4f3eb0SPetr Machata .get_stats_strings = mlxsw_sp1_get_stats_strings,
2752dc4f3eb0SPetr Machata .get_stats = mlxsw_sp1_get_stats,
275324157bc6SDanielle Ratson .txhdr_construct = mlxsw_sp_ptp_txhdr_construct,
2754412cd2adSShalom Toledo };
2755412cd2adSShalom Toledo
2756412cd2adSShalom Toledo static const struct mlxsw_sp_ptp_ops mlxsw_sp2_ptp_ops = {
2757412cd2adSShalom Toledo .clock_init = mlxsw_sp2_ptp_clock_init,
2758412cd2adSShalom Toledo .clock_fini = mlxsw_sp2_ptp_clock_fini,
2759810256ceSPetr Machata .init = mlxsw_sp2_ptp_init,
2760810256ceSPetr Machata .fini = mlxsw_sp2_ptp_fini,
2761aed4b572SPetr Machata .receive = mlxsw_sp2_ptp_receive,
27620714256cSPetr Machata .transmitted = mlxsw_sp2_ptp_transmitted,
276387486427SPetr Machata .hwtstamp_get = mlxsw_sp2_ptp_hwtstamp_get,
276487486427SPetr Machata .hwtstamp_set = mlxsw_sp2_ptp_hwtstamp_set,
27655fc17338SShalom Toledo .shaper_work = mlxsw_sp2_ptp_shaper_work,
276687ee07f8SPetr Machata .get_ts_info = mlxsw_sp2_ptp_get_ts_info,
2767dc4f3eb0SPetr Machata .get_stats_count = mlxsw_sp2_get_stats_count,
2768dc4f3eb0SPetr Machata .get_stats_strings = mlxsw_sp2_get_stats_strings,
2769dc4f3eb0SPetr Machata .get_stats = mlxsw_sp2_get_stats,
277024157bc6SDanielle Ratson .txhdr_construct = mlxsw_sp2_ptp_txhdr_construct,
277124157bc6SDanielle Ratson };
277224157bc6SDanielle Ratson
277324157bc6SDanielle Ratson static const struct mlxsw_sp_ptp_ops mlxsw_sp4_ptp_ops = {
277424157bc6SDanielle Ratson .clock_init = mlxsw_sp2_ptp_clock_init,
277524157bc6SDanielle Ratson .clock_fini = mlxsw_sp2_ptp_clock_fini,
277624157bc6SDanielle Ratson .init = mlxsw_sp2_ptp_init,
277724157bc6SDanielle Ratson .fini = mlxsw_sp2_ptp_fini,
277824157bc6SDanielle Ratson .receive = mlxsw_sp2_ptp_receive,
277924157bc6SDanielle Ratson .transmitted = mlxsw_sp2_ptp_transmitted,
278024157bc6SDanielle Ratson .hwtstamp_get = mlxsw_sp2_ptp_hwtstamp_get,
278124157bc6SDanielle Ratson .hwtstamp_set = mlxsw_sp2_ptp_hwtstamp_set,
278224157bc6SDanielle Ratson .shaper_work = mlxsw_sp2_ptp_shaper_work,
278324157bc6SDanielle Ratson .get_ts_info = mlxsw_sp2_ptp_get_ts_info,
278424157bc6SDanielle Ratson .get_stats_count = mlxsw_sp2_get_stats_count,
278524157bc6SDanielle Ratson .get_stats_strings = mlxsw_sp2_get_stats_strings,
278624157bc6SDanielle Ratson .get_stats = mlxsw_sp2_get_stats,
278724157bc6SDanielle Ratson .txhdr_construct = mlxsw_sp_ptp_txhdr_construct,
2788412cd2adSShalom Toledo };
2789412cd2adSShalom Toledo
27901b9fc42eSIdo Schimmel struct mlxsw_sp_sample_trigger_node {
27911b9fc42eSIdo Schimmel struct mlxsw_sp_sample_trigger trigger;
27921b9fc42eSIdo Schimmel struct mlxsw_sp_sample_params params;
27931b9fc42eSIdo Schimmel struct rhash_head ht_node;
27941b9fc42eSIdo Schimmel struct rcu_head rcu;
27951b9fc42eSIdo Schimmel refcount_t refcount;
27961b9fc42eSIdo Schimmel };
27971b9fc42eSIdo Schimmel
27981b9fc42eSIdo Schimmel static const struct rhashtable_params mlxsw_sp_sample_trigger_ht_params = {
27991b9fc42eSIdo Schimmel .key_offset = offsetof(struct mlxsw_sp_sample_trigger_node, trigger),
28001b9fc42eSIdo Schimmel .head_offset = offsetof(struct mlxsw_sp_sample_trigger_node, ht_node),
28011b9fc42eSIdo Schimmel .key_len = sizeof(struct mlxsw_sp_sample_trigger),
28021b9fc42eSIdo Schimmel .automatic_shrinking = true,
28031b9fc42eSIdo Schimmel };
28041b9fc42eSIdo Schimmel
28051b9fc42eSIdo Schimmel static void
mlxsw_sp_sample_trigger_key_init(struct mlxsw_sp_sample_trigger * key,const struct mlxsw_sp_sample_trigger * trigger)28061b9fc42eSIdo Schimmel mlxsw_sp_sample_trigger_key_init(struct mlxsw_sp_sample_trigger *key,
28071b9fc42eSIdo Schimmel const struct mlxsw_sp_sample_trigger *trigger)
28081b9fc42eSIdo Schimmel {
28091b9fc42eSIdo Schimmel memset(key, 0, sizeof(*key));
28101b9fc42eSIdo Schimmel key->type = trigger->type;
28111b9fc42eSIdo Schimmel key->local_port = trigger->local_port;
28121b9fc42eSIdo Schimmel }
28131b9fc42eSIdo Schimmel
28141b9fc42eSIdo Schimmel /* RCU read lock must be held */
28151b9fc42eSIdo Schimmel struct mlxsw_sp_sample_params *
mlxsw_sp_sample_trigger_params_lookup(struct mlxsw_sp * mlxsw_sp,const struct mlxsw_sp_sample_trigger * trigger)28161b9fc42eSIdo Schimmel mlxsw_sp_sample_trigger_params_lookup(struct mlxsw_sp *mlxsw_sp,
28171b9fc42eSIdo Schimmel const struct mlxsw_sp_sample_trigger *trigger)
28181b9fc42eSIdo Schimmel {
28191b9fc42eSIdo Schimmel struct mlxsw_sp_sample_trigger_node *trigger_node;
28201b9fc42eSIdo Schimmel struct mlxsw_sp_sample_trigger key;
28211b9fc42eSIdo Schimmel
28221b9fc42eSIdo Schimmel mlxsw_sp_sample_trigger_key_init(&key, trigger);
28231b9fc42eSIdo Schimmel trigger_node = rhashtable_lookup(&mlxsw_sp->sample_trigger_ht, &key,
28241b9fc42eSIdo Schimmel mlxsw_sp_sample_trigger_ht_params);
28251b9fc42eSIdo Schimmel if (!trigger_node)
28261b9fc42eSIdo Schimmel return NULL;
28271b9fc42eSIdo Schimmel
28281b9fc42eSIdo Schimmel return &trigger_node->params;
28291b9fc42eSIdo Schimmel }
28301b9fc42eSIdo Schimmel
28311b9fc42eSIdo Schimmel static int
mlxsw_sp_sample_trigger_node_init(struct mlxsw_sp * mlxsw_sp,const struct mlxsw_sp_sample_trigger * trigger,const struct mlxsw_sp_sample_params * params)28321b9fc42eSIdo Schimmel mlxsw_sp_sample_trigger_node_init(struct mlxsw_sp *mlxsw_sp,
28331b9fc42eSIdo Schimmel const struct mlxsw_sp_sample_trigger *trigger,
28341b9fc42eSIdo Schimmel const struct mlxsw_sp_sample_params *params)
28351b9fc42eSIdo Schimmel {
28361b9fc42eSIdo Schimmel struct mlxsw_sp_sample_trigger_node *trigger_node;
28371b9fc42eSIdo Schimmel int err;
28381b9fc42eSIdo Schimmel
28391b9fc42eSIdo Schimmel trigger_node = kzalloc(sizeof(*trigger_node), GFP_KERNEL);
28401b9fc42eSIdo Schimmel if (!trigger_node)
28411b9fc42eSIdo Schimmel return -ENOMEM;
28421b9fc42eSIdo Schimmel
28431b9fc42eSIdo Schimmel trigger_node->trigger = *trigger;
28441b9fc42eSIdo Schimmel trigger_node->params = *params;
28451b9fc42eSIdo Schimmel refcount_set(&trigger_node->refcount, 1);
28461b9fc42eSIdo Schimmel
28471b9fc42eSIdo Schimmel err = rhashtable_insert_fast(&mlxsw_sp->sample_trigger_ht,
28481b9fc42eSIdo Schimmel &trigger_node->ht_node,
28491b9fc42eSIdo Schimmel mlxsw_sp_sample_trigger_ht_params);
28501b9fc42eSIdo Schimmel if (err)
28511b9fc42eSIdo Schimmel goto err_rhashtable_insert;
28521b9fc42eSIdo Schimmel
28531b9fc42eSIdo Schimmel return 0;
28541b9fc42eSIdo Schimmel
28551b9fc42eSIdo Schimmel err_rhashtable_insert:
28561b9fc42eSIdo Schimmel kfree(trigger_node);
28571b9fc42eSIdo Schimmel return err;
28581b9fc42eSIdo Schimmel }
28591b9fc42eSIdo Schimmel
28601b9fc42eSIdo Schimmel static void
mlxsw_sp_sample_trigger_node_fini(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_sample_trigger_node * trigger_node)28611b9fc42eSIdo Schimmel mlxsw_sp_sample_trigger_node_fini(struct mlxsw_sp *mlxsw_sp,
28621b9fc42eSIdo Schimmel struct mlxsw_sp_sample_trigger_node *trigger_node)
28631b9fc42eSIdo Schimmel {
28641b9fc42eSIdo Schimmel rhashtable_remove_fast(&mlxsw_sp->sample_trigger_ht,
28651b9fc42eSIdo Schimmel &trigger_node->ht_node,
28661b9fc42eSIdo Schimmel mlxsw_sp_sample_trigger_ht_params);
28671b9fc42eSIdo Schimmel kfree_rcu(trigger_node, rcu);
28681b9fc42eSIdo Schimmel }
28691b9fc42eSIdo Schimmel
28701b9fc42eSIdo Schimmel int
mlxsw_sp_sample_trigger_params_set(struct mlxsw_sp * mlxsw_sp,const struct mlxsw_sp_sample_trigger * trigger,const struct mlxsw_sp_sample_params * params,struct netlink_ext_ack * extack)28711b9fc42eSIdo Schimmel mlxsw_sp_sample_trigger_params_set(struct mlxsw_sp *mlxsw_sp,
28721b9fc42eSIdo Schimmel const struct mlxsw_sp_sample_trigger *trigger,
28731b9fc42eSIdo Schimmel const struct mlxsw_sp_sample_params *params,
28741b9fc42eSIdo Schimmel struct netlink_ext_ack *extack)
28751b9fc42eSIdo Schimmel {
28761b9fc42eSIdo Schimmel struct mlxsw_sp_sample_trigger_node *trigger_node;
28771b9fc42eSIdo Schimmel struct mlxsw_sp_sample_trigger key;
28781b9fc42eSIdo Schimmel
28791b9fc42eSIdo Schimmel ASSERT_RTNL();
28801b9fc42eSIdo Schimmel
28811b9fc42eSIdo Schimmel mlxsw_sp_sample_trigger_key_init(&key, trigger);
28821b9fc42eSIdo Schimmel
28831b9fc42eSIdo Schimmel trigger_node = rhashtable_lookup_fast(&mlxsw_sp->sample_trigger_ht,
28841b9fc42eSIdo Schimmel &key,
28851b9fc42eSIdo Schimmel mlxsw_sp_sample_trigger_ht_params);
28861b9fc42eSIdo Schimmel if (!trigger_node)
28871b9fc42eSIdo Schimmel return mlxsw_sp_sample_trigger_node_init(mlxsw_sp, &key,
28881b9fc42eSIdo Schimmel params);
28891b9fc42eSIdo Schimmel
289017b96a5cSIdo Schimmel if (trigger_node->trigger.local_port) {
289117b96a5cSIdo Schimmel NL_SET_ERR_MSG_MOD(extack, "Sampling already enabled on port");
289217b96a5cSIdo Schimmel return -EINVAL;
289317b96a5cSIdo Schimmel }
289417b96a5cSIdo Schimmel
28951b9fc42eSIdo Schimmel if (trigger_node->params.psample_group != params->psample_group ||
28961b9fc42eSIdo Schimmel trigger_node->params.truncate != params->truncate ||
28971b9fc42eSIdo Schimmel trigger_node->params.rate != params->rate ||
28981b9fc42eSIdo Schimmel trigger_node->params.trunc_size != params->trunc_size) {
28991b9fc42eSIdo Schimmel NL_SET_ERR_MSG_MOD(extack, "Sampling parameters do not match for an existing sampling trigger");
29001b9fc42eSIdo Schimmel return -EINVAL;
29011b9fc42eSIdo Schimmel }
29021b9fc42eSIdo Schimmel
29031b9fc42eSIdo Schimmel refcount_inc(&trigger_node->refcount);
29041b9fc42eSIdo Schimmel
29051b9fc42eSIdo Schimmel return 0;
29061b9fc42eSIdo Schimmel }
29071b9fc42eSIdo Schimmel
29081b9fc42eSIdo Schimmel void
mlxsw_sp_sample_trigger_params_unset(struct mlxsw_sp * mlxsw_sp,const struct mlxsw_sp_sample_trigger * trigger)29091b9fc42eSIdo Schimmel mlxsw_sp_sample_trigger_params_unset(struct mlxsw_sp *mlxsw_sp,
29101b9fc42eSIdo Schimmel const struct mlxsw_sp_sample_trigger *trigger)
29111b9fc42eSIdo Schimmel {
29121b9fc42eSIdo Schimmel struct mlxsw_sp_sample_trigger_node *trigger_node;
29131b9fc42eSIdo Schimmel struct mlxsw_sp_sample_trigger key;
29141b9fc42eSIdo Schimmel
29151b9fc42eSIdo Schimmel ASSERT_RTNL();
29161b9fc42eSIdo Schimmel
29171b9fc42eSIdo Schimmel mlxsw_sp_sample_trigger_key_init(&key, trigger);
29181b9fc42eSIdo Schimmel
29191b9fc42eSIdo Schimmel trigger_node = rhashtable_lookup_fast(&mlxsw_sp->sample_trigger_ht,
29201b9fc42eSIdo Schimmel &key,
29211b9fc42eSIdo Schimmel mlxsw_sp_sample_trigger_ht_params);
29221b9fc42eSIdo Schimmel if (!trigger_node)
29231b9fc42eSIdo Schimmel return;
29241b9fc42eSIdo Schimmel
29251b9fc42eSIdo Schimmel if (!refcount_dec_and_test(&trigger_node->refcount))
29261b9fc42eSIdo Schimmel return;
29271b9fc42eSIdo Schimmel
29281b9fc42eSIdo Schimmel mlxsw_sp_sample_trigger_node_fini(mlxsw_sp, trigger_node);
29291b9fc42eSIdo Schimmel }
29301b9fc42eSIdo Schimmel
2931c30f5d01SPetr Machata static int mlxsw_sp_netdevice_event(struct notifier_block *unused,
2932c30f5d01SPetr Machata unsigned long event, void *ptr);
2933c30f5d01SPetr Machata
29342d91f080SAmit Cohen #define MLXSW_SP_DEFAULT_PARSING_DEPTH 96
29352d91f080SAmit Cohen #define MLXSW_SP_INCREASED_PARSING_DEPTH 128
29362d91f080SAmit Cohen #define MLXSW_SP_DEFAULT_VXLAN_UDP_DPORT 4789
29372d91f080SAmit Cohen
mlxsw_sp_parsing_init(struct mlxsw_sp * mlxsw_sp)29382d91f080SAmit Cohen static void mlxsw_sp_parsing_init(struct mlxsw_sp *mlxsw_sp)
29392d91f080SAmit Cohen {
294035c35692SIdo Schimmel refcount_set(&mlxsw_sp->parsing.parsing_depth_ref, 0);
29412d91f080SAmit Cohen mlxsw_sp->parsing.parsing_depth = MLXSW_SP_DEFAULT_PARSING_DEPTH;
29422d91f080SAmit Cohen mlxsw_sp->parsing.vxlan_udp_dport = MLXSW_SP_DEFAULT_VXLAN_UDP_DPORT;
29432d91f080SAmit Cohen mutex_init(&mlxsw_sp->parsing.lock);
29442d91f080SAmit Cohen }
29452d91f080SAmit Cohen
mlxsw_sp_parsing_fini(struct mlxsw_sp * mlxsw_sp)29462d91f080SAmit Cohen static void mlxsw_sp_parsing_fini(struct mlxsw_sp *mlxsw_sp)
29472d91f080SAmit Cohen {
29482d91f080SAmit Cohen mutex_destroy(&mlxsw_sp->parsing.lock);
294935c35692SIdo Schimmel WARN_ON_ONCE(refcount_read(&mlxsw_sp->parsing.parsing_depth_ref));
29502d91f080SAmit Cohen }
29512d91f080SAmit Cohen
2952e846efe2SAmit Cohen struct mlxsw_sp_ipv6_addr_node {
2953e846efe2SAmit Cohen struct in6_addr key;
2954e846efe2SAmit Cohen struct rhash_head ht_node;
2955e846efe2SAmit Cohen u32 kvdl_index;
2956e846efe2SAmit Cohen refcount_t refcount;
2957e846efe2SAmit Cohen };
2958e846efe2SAmit Cohen
2959e846efe2SAmit Cohen static const struct rhashtable_params mlxsw_sp_ipv6_addr_ht_params = {
2960e846efe2SAmit Cohen .key_offset = offsetof(struct mlxsw_sp_ipv6_addr_node, key),
2961e846efe2SAmit Cohen .head_offset = offsetof(struct mlxsw_sp_ipv6_addr_node, ht_node),
2962e846efe2SAmit Cohen .key_len = sizeof(struct in6_addr),
2963e846efe2SAmit Cohen .automatic_shrinking = true,
2964e846efe2SAmit Cohen };
2965e846efe2SAmit Cohen
2966e846efe2SAmit Cohen static int
mlxsw_sp_ipv6_addr_init(struct mlxsw_sp * mlxsw_sp,const struct in6_addr * addr6,u32 * p_kvdl_index)2967e846efe2SAmit Cohen mlxsw_sp_ipv6_addr_init(struct mlxsw_sp *mlxsw_sp, const struct in6_addr *addr6,
2968e846efe2SAmit Cohen u32 *p_kvdl_index)
2969e846efe2SAmit Cohen {
2970e846efe2SAmit Cohen struct mlxsw_sp_ipv6_addr_node *node;
2971e846efe2SAmit Cohen char rips_pl[MLXSW_REG_RIPS_LEN];
2972e846efe2SAmit Cohen int err;
2973e846efe2SAmit Cohen
2974e846efe2SAmit Cohen err = mlxsw_sp_kvdl_alloc(mlxsw_sp,
2975e846efe2SAmit Cohen MLXSW_SP_KVDL_ENTRY_TYPE_IPV6_ADDRESS, 1,
2976e846efe2SAmit Cohen p_kvdl_index);
2977e846efe2SAmit Cohen if (err)
2978e846efe2SAmit Cohen return err;
2979e846efe2SAmit Cohen
2980e846efe2SAmit Cohen mlxsw_reg_rips_pack(rips_pl, *p_kvdl_index, addr6);
2981e846efe2SAmit Cohen err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(rips), rips_pl);
2982e846efe2SAmit Cohen if (err)
2983e846efe2SAmit Cohen goto err_rips_write;
2984e846efe2SAmit Cohen
2985e846efe2SAmit Cohen node = kzalloc(sizeof(*node), GFP_KERNEL);
2986e846efe2SAmit Cohen if (!node) {
2987e846efe2SAmit Cohen err = -ENOMEM;
2988e846efe2SAmit Cohen goto err_node_alloc;
2989e846efe2SAmit Cohen }
2990e846efe2SAmit Cohen
2991e846efe2SAmit Cohen node->key = *addr6;
2992e846efe2SAmit Cohen node->kvdl_index = *p_kvdl_index;
2993e846efe2SAmit Cohen refcount_set(&node->refcount, 1);
2994e846efe2SAmit Cohen
2995e846efe2SAmit Cohen err = rhashtable_insert_fast(&mlxsw_sp->ipv6_addr_ht,
2996e846efe2SAmit Cohen &node->ht_node,
2997e846efe2SAmit Cohen mlxsw_sp_ipv6_addr_ht_params);
2998e846efe2SAmit Cohen if (err)
2999e846efe2SAmit Cohen goto err_rhashtable_insert;
3000e846efe2SAmit Cohen
3001e846efe2SAmit Cohen return 0;
3002e846efe2SAmit Cohen
3003e846efe2SAmit Cohen err_rhashtable_insert:
3004e846efe2SAmit Cohen kfree(node);
3005e846efe2SAmit Cohen err_node_alloc:
3006e846efe2SAmit Cohen err_rips_write:
3007e846efe2SAmit Cohen mlxsw_sp_kvdl_free(mlxsw_sp, MLXSW_SP_KVDL_ENTRY_TYPE_IPV6_ADDRESS, 1,
3008e846efe2SAmit Cohen *p_kvdl_index);
3009e846efe2SAmit Cohen return err;
3010e846efe2SAmit Cohen }
3011e846efe2SAmit Cohen
mlxsw_sp_ipv6_addr_fini(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_ipv6_addr_node * node)3012e846efe2SAmit Cohen static void mlxsw_sp_ipv6_addr_fini(struct mlxsw_sp *mlxsw_sp,
3013e846efe2SAmit Cohen struct mlxsw_sp_ipv6_addr_node *node)
3014e846efe2SAmit Cohen {
3015e846efe2SAmit Cohen u32 kvdl_index = node->kvdl_index;
3016e846efe2SAmit Cohen
3017e846efe2SAmit Cohen rhashtable_remove_fast(&mlxsw_sp->ipv6_addr_ht, &node->ht_node,
3018e846efe2SAmit Cohen mlxsw_sp_ipv6_addr_ht_params);
3019e846efe2SAmit Cohen kfree(node);
3020e846efe2SAmit Cohen mlxsw_sp_kvdl_free(mlxsw_sp, MLXSW_SP_KVDL_ENTRY_TYPE_IPV6_ADDRESS, 1,
3021e846efe2SAmit Cohen kvdl_index);
3022e846efe2SAmit Cohen }
3023e846efe2SAmit Cohen
mlxsw_sp_ipv6_addr_kvdl_index_get(struct mlxsw_sp * mlxsw_sp,const struct in6_addr * addr6,u32 * p_kvdl_index)3024e846efe2SAmit Cohen int mlxsw_sp_ipv6_addr_kvdl_index_get(struct mlxsw_sp *mlxsw_sp,
3025e846efe2SAmit Cohen const struct in6_addr *addr6,
3026e846efe2SAmit Cohen u32 *p_kvdl_index)
3027e846efe2SAmit Cohen {
3028e846efe2SAmit Cohen struct mlxsw_sp_ipv6_addr_node *node;
3029e846efe2SAmit Cohen int err = 0;
3030e846efe2SAmit Cohen
3031e846efe2SAmit Cohen mutex_lock(&mlxsw_sp->ipv6_addr_ht_lock);
3032e846efe2SAmit Cohen node = rhashtable_lookup_fast(&mlxsw_sp->ipv6_addr_ht, addr6,
3033e846efe2SAmit Cohen mlxsw_sp_ipv6_addr_ht_params);
3034e846efe2SAmit Cohen if (node) {
3035e846efe2SAmit Cohen refcount_inc(&node->refcount);
3036e846efe2SAmit Cohen *p_kvdl_index = node->kvdl_index;
3037e846efe2SAmit Cohen goto out_unlock;
3038e846efe2SAmit Cohen }
3039e846efe2SAmit Cohen
3040e846efe2SAmit Cohen err = mlxsw_sp_ipv6_addr_init(mlxsw_sp, addr6, p_kvdl_index);
3041e846efe2SAmit Cohen
3042e846efe2SAmit Cohen out_unlock:
3043e846efe2SAmit Cohen mutex_unlock(&mlxsw_sp->ipv6_addr_ht_lock);
3044e846efe2SAmit Cohen return err;
3045e846efe2SAmit Cohen }
3046e846efe2SAmit Cohen
3047e846efe2SAmit Cohen void
mlxsw_sp_ipv6_addr_put(struct mlxsw_sp * mlxsw_sp,const struct in6_addr * addr6)3048e846efe2SAmit Cohen mlxsw_sp_ipv6_addr_put(struct mlxsw_sp *mlxsw_sp, const struct in6_addr *addr6)
3049e846efe2SAmit Cohen {
3050e846efe2SAmit Cohen struct mlxsw_sp_ipv6_addr_node *node;
3051e846efe2SAmit Cohen
3052e846efe2SAmit Cohen mutex_lock(&mlxsw_sp->ipv6_addr_ht_lock);
3053e846efe2SAmit Cohen node = rhashtable_lookup_fast(&mlxsw_sp->ipv6_addr_ht, addr6,
3054e846efe2SAmit Cohen mlxsw_sp_ipv6_addr_ht_params);
3055e846efe2SAmit Cohen if (WARN_ON(!node))
3056e846efe2SAmit Cohen goto out_unlock;
3057e846efe2SAmit Cohen
3058e846efe2SAmit Cohen if (!refcount_dec_and_test(&node->refcount))
3059e846efe2SAmit Cohen goto out_unlock;
3060e846efe2SAmit Cohen
3061e846efe2SAmit Cohen mlxsw_sp_ipv6_addr_fini(mlxsw_sp, node);
3062e846efe2SAmit Cohen
3063e846efe2SAmit Cohen out_unlock:
3064e846efe2SAmit Cohen mutex_unlock(&mlxsw_sp->ipv6_addr_ht_lock);
3065e846efe2SAmit Cohen }
3066e846efe2SAmit Cohen
mlxsw_sp_ipv6_addr_ht_init(struct mlxsw_sp * mlxsw_sp)3067e846efe2SAmit Cohen static int mlxsw_sp_ipv6_addr_ht_init(struct mlxsw_sp *mlxsw_sp)
3068e846efe2SAmit Cohen {
3069e846efe2SAmit Cohen int err;
3070e846efe2SAmit Cohen
3071e846efe2SAmit Cohen err = rhashtable_init(&mlxsw_sp->ipv6_addr_ht,
3072e846efe2SAmit Cohen &mlxsw_sp_ipv6_addr_ht_params);
3073e846efe2SAmit Cohen if (err)
3074e846efe2SAmit Cohen return err;
3075e846efe2SAmit Cohen
3076e846efe2SAmit Cohen mutex_init(&mlxsw_sp->ipv6_addr_ht_lock);
3077e846efe2SAmit Cohen return 0;
3078e846efe2SAmit Cohen }
3079e846efe2SAmit Cohen
mlxsw_sp_ipv6_addr_ht_fini(struct mlxsw_sp * mlxsw_sp)3080e846efe2SAmit Cohen static void mlxsw_sp_ipv6_addr_ht_fini(struct mlxsw_sp *mlxsw_sp)
3081e846efe2SAmit Cohen {
3082e846efe2SAmit Cohen mutex_destroy(&mlxsw_sp->ipv6_addr_ht_lock);
3083e846efe2SAmit Cohen rhashtable_destroy(&mlxsw_sp->ipv6_addr_ht);
3084e846efe2SAmit Cohen }
3085e846efe2SAmit Cohen
mlxsw_sp_init(struct mlxsw_core * mlxsw_core,const struct mlxsw_bus_info * mlxsw_bus_info,struct netlink_ext_ack * extack)3086b2f10571SJiri Pirko static int mlxsw_sp_init(struct mlxsw_core *mlxsw_core,
30875bcfb6a4SJiri Pirko const struct mlxsw_bus_info *mlxsw_bus_info,
30885bcfb6a4SJiri Pirko struct netlink_ext_ack *extack)
308956ade8feSJiri Pirko {
3090b2f10571SJiri Pirko struct mlxsw_sp *mlxsw_sp = mlxsw_core_driver_priv(mlxsw_core);
309156ade8feSJiri Pirko int err;
309256ade8feSJiri Pirko
309356ade8feSJiri Pirko mlxsw_sp->core = mlxsw_core;
309456ade8feSJiri Pirko mlxsw_sp->bus_info = mlxsw_bus_info;
309556ade8feSJiri Pirko
30962d91f080SAmit Cohen mlxsw_sp_parsing_init(mlxsw_sp);
30979032b9e8SShalom Toledo
309856ade8feSJiri Pirko err = mlxsw_sp_base_mac_get(mlxsw_sp);
309956ade8feSJiri Pirko if (err) {
310056ade8feSJiri Pirko dev_err(mlxsw_sp->bus_info->dev, "Failed to get base mac\n");
310156ade8feSJiri Pirko return err;
310256ade8feSJiri Pirko }
310356ade8feSJiri Pirko
3104a875a2eeSIdo Schimmel err = mlxsw_sp_kvdl_init(mlxsw_sp);
3105a875a2eeSIdo Schimmel if (err) {
3106a875a2eeSIdo Schimmel dev_err(mlxsw_sp->bus_info->dev, "Failed to initialize KVDL\n");
3107a875a2eeSIdo Schimmel return err;
3108a875a2eeSIdo Schimmel }
3109a875a2eeSIdo Schimmel
3110bb1bba35SAmit Cohen err = mlxsw_sp_pgt_init(mlxsw_sp);
3111bb1bba35SAmit Cohen if (err) {
3112bb1bba35SAmit Cohen dev_err(mlxsw_sp->bus_info->dev, "Failed to initialize PGT\n");
3113bb1bba35SAmit Cohen goto err_pgt_init;
3114bb1bba35SAmit Cohen }
3115bb1bba35SAmit Cohen
3116a1107487SIdo Schimmel err = mlxsw_sp_fids_init(mlxsw_sp);
311756ade8feSJiri Pirko if (err) {
3118a1107487SIdo Schimmel dev_err(mlxsw_sp->bus_info->dev, "Failed to initialize FIDs\n");
3119a875a2eeSIdo Schimmel goto err_fids_init;
312056ade8feSJiri Pirko }
312156ade8feSJiri Pirko
31228d3fbae7SIdo Schimmel err = mlxsw_sp_policers_init(mlxsw_sp);
31238d3fbae7SIdo Schimmel if (err) {
31248d3fbae7SIdo Schimmel dev_err(mlxsw_sp->bus_info->dev, "Failed to initialize policers\n");
31258d3fbae7SIdo Schimmel goto err_policers_init;
31268d3fbae7SIdo Schimmel }
31278d3fbae7SIdo Schimmel
3128a1107487SIdo Schimmel err = mlxsw_sp_traps_init(mlxsw_sp);
312956ade8feSJiri Pirko if (err) {
3130a1107487SIdo Schimmel dev_err(mlxsw_sp->bus_info->dev, "Failed to set traps\n");
3131a1107487SIdo Schimmel goto err_traps_init;
313256ade8feSJiri Pirko }
313356ade8feSJiri Pirko
3134b5ce611fSIdo Schimmel err = mlxsw_sp_devlink_traps_init(mlxsw_sp);
3135b5ce611fSIdo Schimmel if (err) {
3136b5ce611fSIdo Schimmel dev_err(mlxsw_sp->bus_info->dev, "Failed to initialize devlink traps\n");
3137b5ce611fSIdo Schimmel goto err_devlink_traps_init;
3138b5ce611fSIdo Schimmel }
3139b5ce611fSIdo Schimmel
314056ade8feSJiri Pirko err = mlxsw_sp_buffers_init(mlxsw_sp);
314156ade8feSJiri Pirko if (err) {
314256ade8feSJiri Pirko dev_err(mlxsw_sp->bus_info->dev, "Failed to initialize buffers\n");
314356ade8feSJiri Pirko goto err_buffers_init;
314456ade8feSJiri Pirko }
314556ade8feSJiri Pirko
31460d65fc13SJiri Pirko err = mlxsw_sp_lag_init(mlxsw_sp);
31470d65fc13SJiri Pirko if (err) {
31480d65fc13SJiri Pirko dev_err(mlxsw_sp->bus_info->dev, "Failed to initialize LAG\n");
31490d65fc13SJiri Pirko goto err_lag_init;
31500d65fc13SJiri Pirko }
31510d65fc13SJiri Pirko
3152cda880deSPetr Machata /* Initialize SPAN before router and switchdev, so that those components
3153cda880deSPetr Machata * can call mlxsw_sp_span_respin().
3154cda880deSPetr Machata */
3155cda880deSPetr Machata err = mlxsw_sp_span_init(mlxsw_sp);
3156cda880deSPetr Machata if (err) {
3157cda880deSPetr Machata dev_err(mlxsw_sp->bus_info->dev, "Failed to init span system\n");
3158cda880deSPetr Machata goto err_span_init;
3159cda880deSPetr Machata }
3160cda880deSPetr Machata
316156ade8feSJiri Pirko err = mlxsw_sp_switchdev_init(mlxsw_sp);
316256ade8feSJiri Pirko if (err) {
316356ade8feSJiri Pirko dev_err(mlxsw_sp->bus_info->dev, "Failed to initialize switchdev\n");
316456ade8feSJiri Pirko goto err_switchdev_init;
316556ade8feSJiri Pirko }
316656ade8feSJiri Pirko
3167e2b2d35aSYotam Gigi err = mlxsw_sp_counter_pool_init(mlxsw_sp);
3168e2b2d35aSYotam Gigi if (err) {
3169e2b2d35aSYotam Gigi dev_err(mlxsw_sp->bus_info->dev, "Failed to init counter pool\n");
3170e2b2d35aSYotam Gigi goto err_counter_pool_init;
3171e2b2d35aSYotam Gigi }
3172e2b2d35aSYotam Gigi
3173d3b939b8SYotam Gigi err = mlxsw_sp_afa_init(mlxsw_sp);
3174d3b939b8SYotam Gigi if (err) {
3175d3b939b8SYotam Gigi dev_err(mlxsw_sp->bus_info->dev, "Failed to initialize ACL actions\n");
3176d3b939b8SYotam Gigi goto err_afa_init;
3177d3b939b8SYotam Gigi }
3178d3b939b8SYotam Gigi
3179e846efe2SAmit Cohen err = mlxsw_sp_ipv6_addr_ht_init(mlxsw_sp);
3180e846efe2SAmit Cohen if (err) {
3181e846efe2SAmit Cohen dev_err(mlxsw_sp->bus_info->dev, "Failed to initialize hash table for IPv6 addresses\n");
3182e846efe2SAmit Cohen goto err_ipv6_addr_ht_init;
3183e846efe2SAmit Cohen }
3184e846efe2SAmit Cohen
31856e6030bdSIdo Schimmel err = mlxsw_sp_nve_init(mlxsw_sp);
31866e6030bdSIdo Schimmel if (err) {
31876e6030bdSIdo Schimmel dev_err(mlxsw_sp->bus_info->dev, "Failed to initialize NVE\n");
31886e6030bdSIdo Schimmel goto err_nve_init;
31896e6030bdSIdo Schimmel }
31906e6030bdSIdo Schimmel
3191b3eb04beSIdo Schimmel err = mlxsw_sp_port_range_init(mlxsw_sp);
3192b3eb04beSIdo Schimmel if (err) {
3193b3eb04beSIdo Schimmel dev_err(mlxsw_sp->bus_info->dev, "Failed to initialize port ranges\n");
3194b3eb04beSIdo Schimmel goto err_port_range_init;
3195b3eb04beSIdo Schimmel }
3196b3eb04beSIdo Schimmel
3197254cec14SNir Dotan err = mlxsw_sp_acl_init(mlxsw_sp);
3198254cec14SNir Dotan if (err) {
3199254cec14SNir Dotan dev_err(mlxsw_sp->bus_info->dev, "Failed to initialize ACL\n");
3200254cec14SNir Dotan goto err_acl_init;
3201254cec14SNir Dotan }
3202254cec14SNir Dotan
32035bcfb6a4SJiri Pirko err = mlxsw_sp_router_init(mlxsw_sp, extack);
3204464dce18SIdo Schimmel if (err) {
3205464dce18SIdo Schimmel dev_err(mlxsw_sp->bus_info->dev, "Failed to initialize router\n");
3206464dce18SIdo Schimmel goto err_router_init;
3207464dce18SIdo Schimmel }
3208464dce18SIdo Schimmel
320933a9583fSDanielle Ratson if (mlxsw_sp->bus_info->read_clock_capable) {
3210412cd2adSShalom Toledo /* NULL is a valid return value from clock_init */
3211412cd2adSShalom Toledo mlxsw_sp->clock =
3212412cd2adSShalom Toledo mlxsw_sp->ptp_ops->clock_init(mlxsw_sp,
3213412cd2adSShalom Toledo mlxsw_sp->bus_info->dev);
3214412cd2adSShalom Toledo if (IS_ERR(mlxsw_sp->clock)) {
3215412cd2adSShalom Toledo err = PTR_ERR(mlxsw_sp->clock);
3216412cd2adSShalom Toledo dev_err(mlxsw_sp->bus_info->dev, "Failed to init ptp clock\n");
3217412cd2adSShalom Toledo goto err_ptp_clock_init;
3218412cd2adSShalom Toledo }
3219412cd2adSShalom Toledo }
3220412cd2adSShalom Toledo
3221810256ceSPetr Machata if (mlxsw_sp->clock) {
3222810256ceSPetr Machata /* NULL is a valid return value from ptp_ops->init */
3223810256ceSPetr Machata mlxsw_sp->ptp_state = mlxsw_sp->ptp_ops->init(mlxsw_sp);
3224810256ceSPetr Machata if (IS_ERR(mlxsw_sp->ptp_state)) {
3225810256ceSPetr Machata err = PTR_ERR(mlxsw_sp->ptp_state);
3226810256ceSPetr Machata dev_err(mlxsw_sp->bus_info->dev, "Failed to initialize PTP\n");
3227810256ceSPetr Machata goto err_ptp_init;
3228810256ceSPetr Machata }
3229810256ceSPetr Machata }
3230810256ceSPetr Machata
323105a8d7d4SPetr Machata /* Initialize netdevice notifier after SPAN is initialized, so that the
323205a8d7d4SPetr Machata * event handler can call SPAN respin.
3233c30f5d01SPetr Machata */
3234c30f5d01SPetr Machata mlxsw_sp->netdevice_nb.notifier_call = mlxsw_sp_netdevice_event;
3235053e92aaSJiri Pirko err = register_netdevice_notifier_net(mlxsw_sp_net(mlxsw_sp),
3236f1cdaa07SJiri Pirko &mlxsw_sp->netdevice_nb);
3237c30f5d01SPetr Machata if (err) {
3238c30f5d01SPetr Machata dev_err(mlxsw_sp->bus_info->dev, "Failed to register netdev notifier\n");
3239c30f5d01SPetr Machata goto err_netdev_notifier;
3240c30f5d01SPetr Machata }
3241c30f5d01SPetr Machata
3242230ead01SArkadi Sharshevsky err = mlxsw_sp_dpipe_init(mlxsw_sp);
3243230ead01SArkadi Sharshevsky if (err) {
3244230ead01SArkadi Sharshevsky dev_err(mlxsw_sp->bus_info->dev, "Failed to init pipeline debug\n");
3245230ead01SArkadi Sharshevsky goto err_dpipe_init;
3246230ead01SArkadi Sharshevsky }
3247230ead01SArkadi Sharshevsky
32484a7f970fSJiri Pirko err = mlxsw_sp_port_module_info_init(mlxsw_sp);
32494a7f970fSJiri Pirko if (err) {
32504a7f970fSJiri Pirko dev_err(mlxsw_sp->bus_info->dev, "Failed to init port module info\n");
32514a7f970fSJiri Pirko goto err_port_module_info_init;
32524a7f970fSJiri Pirko }
32534a7f970fSJiri Pirko
32541b9fc42eSIdo Schimmel err = rhashtable_init(&mlxsw_sp->sample_trigger_ht,
32551b9fc42eSIdo Schimmel &mlxsw_sp_sample_trigger_ht_params);
32561b9fc42eSIdo Schimmel if (err) {
32571b9fc42eSIdo Schimmel dev_err(mlxsw_sp->bus_info->dev, "Failed to init sampling trigger hashtable\n");
32581b9fc42eSIdo Schimmel goto err_sample_trigger_init;
32591b9fc42eSIdo Schimmel }
32601b9fc42eSIdo Schimmel
3261bbf2a475SIdo Schimmel err = mlxsw_sp_ports_create(mlxsw_sp);
3262bbf2a475SIdo Schimmel if (err) {
3263bbf2a475SIdo Schimmel dev_err(mlxsw_sp->bus_info->dev, "Failed to create ports\n");
3264bbf2a475SIdo Schimmel goto err_ports_create;
3265bbf2a475SIdo Schimmel }
3266bbf2a475SIdo Schimmel
326756ade8feSJiri Pirko return 0;
326856ade8feSJiri Pirko
3269bbf2a475SIdo Schimmel err_ports_create:
32701b9fc42eSIdo Schimmel rhashtable_destroy(&mlxsw_sp->sample_trigger_ht);
32711b9fc42eSIdo Schimmel err_sample_trigger_init:
32724a7f970fSJiri Pirko mlxsw_sp_port_module_info_fini(mlxsw_sp);
32734a7f970fSJiri Pirko err_port_module_info_init:
3274230ead01SArkadi Sharshevsky mlxsw_sp_dpipe_fini(mlxsw_sp);
3275230ead01SArkadi Sharshevsky err_dpipe_init:
3276053e92aaSJiri Pirko unregister_netdevice_notifier_net(mlxsw_sp_net(mlxsw_sp),
3277f1cdaa07SJiri Pirko &mlxsw_sp->netdevice_nb);
3278c30f5d01SPetr Machata err_netdev_notifier:
3279412cd2adSShalom Toledo if (mlxsw_sp->clock)
3280810256ceSPetr Machata mlxsw_sp->ptp_ops->fini(mlxsw_sp->ptp_state);
3281810256ceSPetr Machata err_ptp_init:
3282810256ceSPetr Machata if (mlxsw_sp->clock)
3283412cd2adSShalom Toledo mlxsw_sp->ptp_ops->clock_fini(mlxsw_sp->clock);
3284412cd2adSShalom Toledo err_ptp_clock_init:
3285464dce18SIdo Schimmel mlxsw_sp_router_fini(mlxsw_sp);
3286464dce18SIdo Schimmel err_router_init:
3287254cec14SNir Dotan mlxsw_sp_acl_fini(mlxsw_sp);
3288254cec14SNir Dotan err_acl_init:
3289b3eb04beSIdo Schimmel mlxsw_sp_port_range_fini(mlxsw_sp);
3290b3eb04beSIdo Schimmel err_port_range_init:
32916e6030bdSIdo Schimmel mlxsw_sp_nve_fini(mlxsw_sp);
32926e6030bdSIdo Schimmel err_nve_init:
3293e846efe2SAmit Cohen mlxsw_sp_ipv6_addr_ht_fini(mlxsw_sp);
3294e846efe2SAmit Cohen err_ipv6_addr_ht_init:
3295d3b939b8SYotam Gigi mlxsw_sp_afa_fini(mlxsw_sp);
3296d3b939b8SYotam Gigi err_afa_init:
3297e2b2d35aSYotam Gigi mlxsw_sp_counter_pool_fini(mlxsw_sp);
3298e2b2d35aSYotam Gigi err_counter_pool_init:
3299bbf2a475SIdo Schimmel mlxsw_sp_switchdev_fini(mlxsw_sp);
330056ade8feSJiri Pirko err_switchdev_init:
3301cda880deSPetr Machata mlxsw_sp_span_fini(mlxsw_sp);
3302cda880deSPetr Machata err_span_init:
3303ce0bd2b0SNogah Frankel mlxsw_sp_lag_fini(mlxsw_sp);
33040d65fc13SJiri Pirko err_lag_init:
33050f433fa0SJiri Pirko mlxsw_sp_buffers_fini(mlxsw_sp);
330656ade8feSJiri Pirko err_buffers_init:
3307b5ce611fSIdo Schimmel mlxsw_sp_devlink_traps_fini(mlxsw_sp);
3308b5ce611fSIdo Schimmel err_devlink_traps_init:
330956ade8feSJiri Pirko mlxsw_sp_traps_fini(mlxsw_sp);
3310a1107487SIdo Schimmel err_traps_init:
33118d3fbae7SIdo Schimmel mlxsw_sp_policers_fini(mlxsw_sp);
33128d3fbae7SIdo Schimmel err_policers_init:
3313a1107487SIdo Schimmel mlxsw_sp_fids_fini(mlxsw_sp);
3314a875a2eeSIdo Schimmel err_fids_init:
3315bb1bba35SAmit Cohen mlxsw_sp_pgt_fini(mlxsw_sp);
3316bb1bba35SAmit Cohen err_pgt_init:
3317a875a2eeSIdo Schimmel mlxsw_sp_kvdl_fini(mlxsw_sp);
33182d91f080SAmit Cohen mlxsw_sp_parsing_fini(mlxsw_sp);
331956ade8feSJiri Pirko return err;
332056ade8feSJiri Pirko }
332156ade8feSJiri Pirko
mlxsw_sp1_init(struct mlxsw_core * mlxsw_core,const struct mlxsw_bus_info * mlxsw_bus_info,struct netlink_ext_ack * extack)3322c3ab4354SJiri Pirko static int mlxsw_sp1_init(struct mlxsw_core *mlxsw_core,
33235bcfb6a4SJiri Pirko const struct mlxsw_bus_info *mlxsw_bus_info,
33245bcfb6a4SJiri Pirko struct netlink_ext_ack *extack)
3325c3ab4354SJiri Pirko {
3326c3ab4354SJiri Pirko struct mlxsw_sp *mlxsw_sp = mlxsw_core_driver_priv(mlxsw_core);
3327c3ab4354SJiri Pirko
33280f74fa56SAmit Cohen mlxsw_sp->switchdev_ops = &mlxsw_sp1_switchdev_ops;
3329c3ab4354SJiri Pirko mlxsw_sp->kvdl_ops = &mlxsw_sp1_kvdl_ops;
3330c3ab4354SJiri Pirko mlxsw_sp->afa_ops = &mlxsw_sp1_act_afa_ops;
3331c3ab4354SJiri Pirko mlxsw_sp->afk_ops = &mlxsw_sp1_afk_ops;
3332c3ab4354SJiri Pirko mlxsw_sp->mr_tcam_ops = &mlxsw_sp1_mr_tcam_ops;
33333cc9a15aSPetr Machata mlxsw_sp->acl_rulei_ops = &mlxsw_sp1_acl_rulei_ops;
3334c3ab4354SJiri Pirko mlxsw_sp->acl_tcam_ops = &mlxsw_sp1_acl_tcam_ops;
33356e6030bdSIdo Schimmel mlxsw_sp->nve_ops_arr = mlxsw_sp1_nve_ops_arr;
33369329b816SPetr Machata mlxsw_sp->mac_mask = mlxsw_sp1_mac_mask;
3337c39f3e0eSPetr Machata mlxsw_sp->sb_vals = &mlxsw_sp1_sb_vals;
3338a41b9626SPetr Machata mlxsw_sp->sb_ops = &mlxsw_sp1_sb_ops;
3339c5b870dfSShalom Toledo mlxsw_sp->port_type_speed_ops = &mlxsw_sp1_port_type_speed_ops;
3340412cd2adSShalom Toledo mlxsw_sp->ptp_ops = &mlxsw_sp1_ptp_ops;
3341ff9fdfecSJiri Pirko mlxsw_sp->span_ops = &mlxsw_sp1_span_ops;
33428d3fbae7SIdo Schimmel mlxsw_sp->policer_core_ops = &mlxsw_sp1_policer_core_ops;
334336d1fd68SIdo Schimmel mlxsw_sp->trap_ops = &mlxsw_sp1_trap_ops;
334420afb9bcSIdo Schimmel mlxsw_sp->mall_ops = &mlxsw_sp1_mall_ops;
3345d354fdd9SIdo Schimmel mlxsw_sp->router_ops = &mlxsw_sp1_router_ops;
3346dadbc6bcSPetr Machata mlxsw_sp->listeners = mlxsw_sp1_listener;
3347dadbc6bcSPetr Machata mlxsw_sp->listeners_count = ARRAY_SIZE(mlxsw_sp1_listener);
334804e85970SAmit Cohen mlxsw_sp->fid_family_arr = mlxsw_sp1_fid_family_arr;
334947259544SPetr Machata mlxsw_sp->lowest_shaper_bs = MLXSW_REG_QEEC_LOWEST_SHAPER_BS_SP1;
3350a1697d11SAmit Cohen mlxsw_sp->pgt_smpe_index_valid = true;
3351c3ab4354SJiri Pirko
33525bcfb6a4SJiri Pirko return mlxsw_sp_init(mlxsw_core, mlxsw_bus_info, extack);
3353c3ab4354SJiri Pirko }
3354c3ab4354SJiri Pirko
mlxsw_sp2_init(struct mlxsw_core * mlxsw_core,const struct mlxsw_bus_info * mlxsw_bus_info,struct netlink_ext_ack * extack)3355c3ab4354SJiri Pirko static int mlxsw_sp2_init(struct mlxsw_core *mlxsw_core,
33565bcfb6a4SJiri Pirko const struct mlxsw_bus_info *mlxsw_bus_info,
33575bcfb6a4SJiri Pirko struct netlink_ext_ack *extack)
3358c3ab4354SJiri Pirko {
3359c3ab4354SJiri Pirko struct mlxsw_sp *mlxsw_sp = mlxsw_core_driver_priv(mlxsw_core);
3360c3ab4354SJiri Pirko
33610f74fa56SAmit Cohen mlxsw_sp->switchdev_ops = &mlxsw_sp2_switchdev_ops;
3362c3ab4354SJiri Pirko mlxsw_sp->kvdl_ops = &mlxsw_sp2_kvdl_ops;
3363c3ab4354SJiri Pirko mlxsw_sp->afa_ops = &mlxsw_sp2_act_afa_ops;
3364c3ab4354SJiri Pirko mlxsw_sp->afk_ops = &mlxsw_sp2_afk_ops;
3365c3ab4354SJiri Pirko mlxsw_sp->mr_tcam_ops = &mlxsw_sp2_mr_tcam_ops;
33663cc9a15aSPetr Machata mlxsw_sp->acl_rulei_ops = &mlxsw_sp2_acl_rulei_ops;
3367c3ab4354SJiri Pirko mlxsw_sp->acl_tcam_ops = &mlxsw_sp2_acl_tcam_ops;
336858723d2fSAmit Cohen mlxsw_sp->acl_bf_ops = &mlxsw_sp2_acl_bf_ops;
33696e6030bdSIdo Schimmel mlxsw_sp->nve_ops_arr = mlxsw_sp2_nve_ops_arr;
33709329b816SPetr Machata mlxsw_sp->mac_mask = mlxsw_sp2_mac_mask;
3371c39f3e0eSPetr Machata mlxsw_sp->sb_vals = &mlxsw_sp2_sb_vals;
3372a41b9626SPetr Machata mlxsw_sp->sb_ops = &mlxsw_sp2_sb_ops;
3373d3eaf108SShalom Toledo mlxsw_sp->port_type_speed_ops = &mlxsw_sp2_port_type_speed_ops;
3374412cd2adSShalom Toledo mlxsw_sp->ptp_ops = &mlxsw_sp2_ptp_ops;
3375ff9fdfecSJiri Pirko mlxsw_sp->span_ops = &mlxsw_sp2_span_ops;
33768d3fbae7SIdo Schimmel mlxsw_sp->policer_core_ops = &mlxsw_sp2_policer_core_ops;
337736d1fd68SIdo Schimmel mlxsw_sp->trap_ops = &mlxsw_sp2_trap_ops;
337820afb9bcSIdo Schimmel mlxsw_sp->mall_ops = &mlxsw_sp2_mall_ops;
3379d354fdd9SIdo Schimmel mlxsw_sp->router_ops = &mlxsw_sp2_router_ops;
3380b0ec003eSJiri Pirko mlxsw_sp->listeners = mlxsw_sp2_listener;
3381b0ec003eSJiri Pirko mlxsw_sp->listeners_count = ARRAY_SIZE(mlxsw_sp2_listener);
338204e85970SAmit Cohen mlxsw_sp->fid_family_arr = mlxsw_sp2_fid_family_arr;
338347259544SPetr Machata mlxsw_sp->lowest_shaper_bs = MLXSW_REG_QEEC_LOWEST_SHAPER_BS_SP2;
3384a1697d11SAmit Cohen mlxsw_sp->pgt_smpe_index_valid = false;
3385c3ab4354SJiri Pirko
33865bcfb6a4SJiri Pirko return mlxsw_sp_init(mlxsw_core, mlxsw_bus_info, extack);
3387c3ab4354SJiri Pirko }
3388c3ab4354SJiri Pirko
mlxsw_sp3_init(struct mlxsw_core * mlxsw_core,const struct mlxsw_bus_info * mlxsw_bus_info,struct netlink_ext_ack * extack)3389d58c35caSIdo Schimmel static int mlxsw_sp3_init(struct mlxsw_core *mlxsw_core,
3390d58c35caSIdo Schimmel const struct mlxsw_bus_info *mlxsw_bus_info,
3391d58c35caSIdo Schimmel struct netlink_ext_ack *extack)
3392d58c35caSIdo Schimmel {
3393d58c35caSIdo Schimmel struct mlxsw_sp *mlxsw_sp = mlxsw_core_driver_priv(mlxsw_core);
3394d58c35caSIdo Schimmel
33950f74fa56SAmit Cohen mlxsw_sp->switchdev_ops = &mlxsw_sp2_switchdev_ops;
3396d58c35caSIdo Schimmel mlxsw_sp->kvdl_ops = &mlxsw_sp2_kvdl_ops;
3397d58c35caSIdo Schimmel mlxsw_sp->afa_ops = &mlxsw_sp2_act_afa_ops;
3398d58c35caSIdo Schimmel mlxsw_sp->afk_ops = &mlxsw_sp2_afk_ops;
3399d58c35caSIdo Schimmel mlxsw_sp->mr_tcam_ops = &mlxsw_sp2_mr_tcam_ops;
34003cc9a15aSPetr Machata mlxsw_sp->acl_rulei_ops = &mlxsw_sp2_acl_rulei_ops;
3401d58c35caSIdo Schimmel mlxsw_sp->acl_tcam_ops = &mlxsw_sp2_acl_tcam_ops;
340258723d2fSAmit Cohen mlxsw_sp->acl_bf_ops = &mlxsw_sp2_acl_bf_ops;
3403d58c35caSIdo Schimmel mlxsw_sp->nve_ops_arr = mlxsw_sp2_nve_ops_arr;
3404d58c35caSIdo Schimmel mlxsw_sp->mac_mask = mlxsw_sp2_mac_mask;
3405d58c35caSIdo Schimmel mlxsw_sp->sb_vals = &mlxsw_sp2_sb_vals;
3406a41b9626SPetr Machata mlxsw_sp->sb_ops = &mlxsw_sp3_sb_ops;
3407d58c35caSIdo Schimmel mlxsw_sp->port_type_speed_ops = &mlxsw_sp2_port_type_speed_ops;
3408d58c35caSIdo Schimmel mlxsw_sp->ptp_ops = &mlxsw_sp2_ptp_ops;
34093b909c55SPetr Machata mlxsw_sp->span_ops = &mlxsw_sp3_span_ops;
34108d3fbae7SIdo Schimmel mlxsw_sp->policer_core_ops = &mlxsw_sp2_policer_core_ops;
341136d1fd68SIdo Schimmel mlxsw_sp->trap_ops = &mlxsw_sp2_trap_ops;
341220afb9bcSIdo Schimmel mlxsw_sp->mall_ops = &mlxsw_sp2_mall_ops;
3413d354fdd9SIdo Schimmel mlxsw_sp->router_ops = &mlxsw_sp2_router_ops;
3414b0ec003eSJiri Pirko mlxsw_sp->listeners = mlxsw_sp2_listener;
3415b0ec003eSJiri Pirko mlxsw_sp->listeners_count = ARRAY_SIZE(mlxsw_sp2_listener);
341604e85970SAmit Cohen mlxsw_sp->fid_family_arr = mlxsw_sp2_fid_family_arr;
341747259544SPetr Machata mlxsw_sp->lowest_shaper_bs = MLXSW_REG_QEEC_LOWEST_SHAPER_BS_SP3;
3418a1697d11SAmit Cohen mlxsw_sp->pgt_smpe_index_valid = false;
3419d58c35caSIdo Schimmel
3420d58c35caSIdo Schimmel return mlxsw_sp_init(mlxsw_core, mlxsw_bus_info, extack);
3421d58c35caSIdo Schimmel }
3422d58c35caSIdo Schimmel
mlxsw_sp4_init(struct mlxsw_core * mlxsw_core,const struct mlxsw_bus_info * mlxsw_bus_info,struct netlink_ext_ack * extack)342347354021SAmit Cohen static int mlxsw_sp4_init(struct mlxsw_core *mlxsw_core,
342447354021SAmit Cohen const struct mlxsw_bus_info *mlxsw_bus_info,
342547354021SAmit Cohen struct netlink_ext_ack *extack)
342647354021SAmit Cohen {
342747354021SAmit Cohen struct mlxsw_sp *mlxsw_sp = mlxsw_core_driver_priv(mlxsw_core);
342847354021SAmit Cohen
342947354021SAmit Cohen mlxsw_sp->switchdev_ops = &mlxsw_sp2_switchdev_ops;
343047354021SAmit Cohen mlxsw_sp->kvdl_ops = &mlxsw_sp2_kvdl_ops;
343147354021SAmit Cohen mlxsw_sp->afa_ops = &mlxsw_sp2_act_afa_ops;
343247354021SAmit Cohen mlxsw_sp->afk_ops = &mlxsw_sp4_afk_ops;
343347354021SAmit Cohen mlxsw_sp->mr_tcam_ops = &mlxsw_sp2_mr_tcam_ops;
343447354021SAmit Cohen mlxsw_sp->acl_rulei_ops = &mlxsw_sp2_acl_rulei_ops;
343547354021SAmit Cohen mlxsw_sp->acl_tcam_ops = &mlxsw_sp2_acl_tcam_ops;
343647354021SAmit Cohen mlxsw_sp->acl_bf_ops = &mlxsw_sp4_acl_bf_ops;
343747354021SAmit Cohen mlxsw_sp->nve_ops_arr = mlxsw_sp2_nve_ops_arr;
343847354021SAmit Cohen mlxsw_sp->mac_mask = mlxsw_sp2_mac_mask;
343947354021SAmit Cohen mlxsw_sp->sb_vals = &mlxsw_sp2_sb_vals;
344047354021SAmit Cohen mlxsw_sp->sb_ops = &mlxsw_sp3_sb_ops;
344147354021SAmit Cohen mlxsw_sp->port_type_speed_ops = &mlxsw_sp2_port_type_speed_ops;
344224157bc6SDanielle Ratson mlxsw_sp->ptp_ops = &mlxsw_sp4_ptp_ops;
344347354021SAmit Cohen mlxsw_sp->span_ops = &mlxsw_sp3_span_ops;
344447354021SAmit Cohen mlxsw_sp->policer_core_ops = &mlxsw_sp2_policer_core_ops;
344547354021SAmit Cohen mlxsw_sp->trap_ops = &mlxsw_sp2_trap_ops;
344647354021SAmit Cohen mlxsw_sp->mall_ops = &mlxsw_sp2_mall_ops;
344747354021SAmit Cohen mlxsw_sp->router_ops = &mlxsw_sp2_router_ops;
3448b0ec003eSJiri Pirko mlxsw_sp->listeners = mlxsw_sp2_listener;
3449b0ec003eSJiri Pirko mlxsw_sp->listeners_count = ARRAY_SIZE(mlxsw_sp2_listener);
345004e85970SAmit Cohen mlxsw_sp->fid_family_arr = mlxsw_sp2_fid_family_arr;
345147354021SAmit Cohen mlxsw_sp->lowest_shaper_bs = MLXSW_REG_QEEC_LOWEST_SHAPER_BS_SP4;
3452a1697d11SAmit Cohen mlxsw_sp->pgt_smpe_index_valid = false;
345347354021SAmit Cohen
345447354021SAmit Cohen return mlxsw_sp_init(mlxsw_core, mlxsw_bus_info, extack);
345547354021SAmit Cohen }
345647354021SAmit Cohen
mlxsw_sp_fini(struct mlxsw_core * mlxsw_core)3457b2f10571SJiri Pirko static void mlxsw_sp_fini(struct mlxsw_core *mlxsw_core)
345856ade8feSJiri Pirko {
3459b2f10571SJiri Pirko struct mlxsw_sp *mlxsw_sp = mlxsw_core_driver_priv(mlxsw_core);
346056ade8feSJiri Pirko
3461bbf2a475SIdo Schimmel mlxsw_sp_ports_remove(mlxsw_sp);
34621b9fc42eSIdo Schimmel rhashtable_destroy(&mlxsw_sp->sample_trigger_ht);
34634a7f970fSJiri Pirko mlxsw_sp_port_module_info_fini(mlxsw_sp);
3464230ead01SArkadi Sharshevsky mlxsw_sp_dpipe_fini(mlxsw_sp);
3465053e92aaSJiri Pirko unregister_netdevice_notifier_net(mlxsw_sp_net(mlxsw_sp),
3466f1cdaa07SJiri Pirko &mlxsw_sp->netdevice_nb);
3467810256ceSPetr Machata if (mlxsw_sp->clock) {
3468810256ceSPetr Machata mlxsw_sp->ptp_ops->fini(mlxsw_sp->ptp_state);
3469412cd2adSShalom Toledo mlxsw_sp->ptp_ops->clock_fini(mlxsw_sp->clock);
3470810256ceSPetr Machata }
3471464dce18SIdo Schimmel mlxsw_sp_router_fini(mlxsw_sp);
3472254cec14SNir Dotan mlxsw_sp_acl_fini(mlxsw_sp);
3473b3eb04beSIdo Schimmel mlxsw_sp_port_range_fini(mlxsw_sp);
34746e6030bdSIdo Schimmel mlxsw_sp_nve_fini(mlxsw_sp);
3475e846efe2SAmit Cohen mlxsw_sp_ipv6_addr_ht_fini(mlxsw_sp);
3476d3b939b8SYotam Gigi mlxsw_sp_afa_fini(mlxsw_sp);
3477e2b2d35aSYotam Gigi mlxsw_sp_counter_pool_fini(mlxsw_sp);
347856ade8feSJiri Pirko mlxsw_sp_switchdev_fini(mlxsw_sp);
3479cda880deSPetr Machata mlxsw_sp_span_fini(mlxsw_sp);
3480ce0bd2b0SNogah Frankel mlxsw_sp_lag_fini(mlxsw_sp);
34815113bfdbSJiri Pirko mlxsw_sp_buffers_fini(mlxsw_sp);
3482b5ce611fSIdo Schimmel mlxsw_sp_devlink_traps_fini(mlxsw_sp);
348356ade8feSJiri Pirko mlxsw_sp_traps_fini(mlxsw_sp);
34848d3fbae7SIdo Schimmel mlxsw_sp_policers_fini(mlxsw_sp);
3485a1107487SIdo Schimmel mlxsw_sp_fids_fini(mlxsw_sp);
3486bb1bba35SAmit Cohen mlxsw_sp_pgt_fini(mlxsw_sp);
3487a875a2eeSIdo Schimmel mlxsw_sp_kvdl_fini(mlxsw_sp);
34882d91f080SAmit Cohen mlxsw_sp_parsing_fini(mlxsw_sp);
348956ade8feSJiri Pirko }
349056ade8feSJiri Pirko
3491c3ab4354SJiri Pirko static const struct mlxsw_config_profile mlxsw_sp1_config_profile = {
349256ade8feSJiri Pirko .used_flood_mode = 1,
349377b7f83dSAmit Cohen .flood_mode = MLXSW_CMD_MBOX_CONFIG_PROFILE_FLOOD_MODE_CONTROLLED,
349456ade8feSJiri Pirko .used_max_ib_mc = 1,
349556ade8feSJiri Pirko .max_ib_mc = 0,
349656ade8feSJiri Pirko .used_max_pkey = 1,
349756ade8feSJiri Pirko .max_pkey = 0,
349877b7f83dSAmit Cohen .used_ubridge = 1,
349977b7f83dSAmit Cohen .ubridge = 1,
3500110d2d21SJiri Pirko .used_kvd_sizes = 1,
3501f11fbaf8SIdo Schimmel .kvd_hash_single_parts = 59,
3502f11fbaf8SIdo Schimmel .kvd_hash_double_parts = 41,
3503c6022427SJiri Pirko .kvd_linear_size = MLXSW_SP_KVD_LINEAR_SIZE,
350456ade8feSJiri Pirko .swid_config = {
350556ade8feSJiri Pirko {
350656ade8feSJiri Pirko .used_type = 1,
350756ade8feSJiri Pirko .type = MLXSW_PORT_SWID_TYPE_ETH,
350856ade8feSJiri Pirko }
350956ade8feSJiri Pirko },
351056ade8feSJiri Pirko };
351156ade8feSJiri Pirko
3512c3ab4354SJiri Pirko static const struct mlxsw_config_profile mlxsw_sp2_config_profile = {
3513c3ab4354SJiri Pirko .used_flood_mode = 1,
351477b7f83dSAmit Cohen .flood_mode = MLXSW_CMD_MBOX_CONFIG_PROFILE_FLOOD_MODE_CONTROLLED,
3515c3ab4354SJiri Pirko .used_max_ib_mc = 1,
3516c3ab4354SJiri Pirko .max_ib_mc = 0,
3517c3ab4354SJiri Pirko .used_max_pkey = 1,
3518c3ab4354SJiri Pirko .max_pkey = 0,
351977b7f83dSAmit Cohen .used_ubridge = 1,
352077b7f83dSAmit Cohen .ubridge = 1,
3521c3ab4354SJiri Pirko .swid_config = {
3522c3ab4354SJiri Pirko {
3523c3ab4354SJiri Pirko .used_type = 1,
3524c3ab4354SJiri Pirko .type = MLXSW_PORT_SWID_TYPE_ETH,
3525c3ab4354SJiri Pirko }
3526c3ab4354SJiri Pirko },
3527291fcb93SDanielle Ratson .used_cqe_time_stamp_type = 1,
3528291fcb93SDanielle Ratson .cqe_time_stamp_type = MLXSW_CMD_MBOX_CONFIG_PROFILE_CQE_TIME_STAMP_TYPE_UTC,
3529c3ab4354SJiri Pirko };
3530c3ab4354SJiri Pirko
3531c503d8aeSAmit Cohen /* Reduce number of LAGs from full capacity (256) to the maximum supported LAGs
3532c503d8aeSAmit Cohen * in Spectrum-2/3, to avoid regression in number of free entries in the PGT
3533c503d8aeSAmit Cohen * table.
3534c503d8aeSAmit Cohen */
3535c503d8aeSAmit Cohen #define MLXSW_SP4_CONFIG_PROFILE_MAX_LAG 128
3536c503d8aeSAmit Cohen
3537c503d8aeSAmit Cohen static const struct mlxsw_config_profile mlxsw_sp4_config_profile = {
3538c503d8aeSAmit Cohen .used_max_lag = 1,
3539c503d8aeSAmit Cohen .max_lag = MLXSW_SP4_CONFIG_PROFILE_MAX_LAG,
3540c503d8aeSAmit Cohen .used_flood_mode = 1,
3541c503d8aeSAmit Cohen .flood_mode = MLXSW_CMD_MBOX_CONFIG_PROFILE_FLOOD_MODE_CONTROLLED,
3542c503d8aeSAmit Cohen .used_max_ib_mc = 1,
3543c503d8aeSAmit Cohen .max_ib_mc = 0,
3544c503d8aeSAmit Cohen .used_max_pkey = 1,
3545c503d8aeSAmit Cohen .max_pkey = 0,
3546c503d8aeSAmit Cohen .used_ubridge = 1,
3547c503d8aeSAmit Cohen .ubridge = 1,
3548c503d8aeSAmit Cohen .swid_config = {
3549c503d8aeSAmit Cohen {
3550c503d8aeSAmit Cohen .used_type = 1,
3551c503d8aeSAmit Cohen .type = MLXSW_PORT_SWID_TYPE_ETH,
3552c503d8aeSAmit Cohen }
3553c503d8aeSAmit Cohen },
3554c503d8aeSAmit Cohen .used_cqe_time_stamp_type = 1,
3555c503d8aeSAmit Cohen .cqe_time_stamp_type = MLXSW_CMD_MBOX_CONFIG_PROFILE_CQE_TIME_STAMP_TYPE_UTC,
3556c503d8aeSAmit Cohen };
3557c503d8aeSAmit Cohen
3558ef3116e5SArkadi Sharshevsky static void
mlxsw_sp_resource_size_params_prepare(struct mlxsw_core * mlxsw_core,struct devlink_resource_size_params * kvd_size_params,struct devlink_resource_size_params * linear_size_params,struct devlink_resource_size_params * hash_double_size_params,struct devlink_resource_size_params * hash_single_size_params)355977d27096SJiri Pirko mlxsw_sp_resource_size_params_prepare(struct mlxsw_core *mlxsw_core,
356077d27096SJiri Pirko struct devlink_resource_size_params *kvd_size_params,
356177d27096SJiri Pirko struct devlink_resource_size_params *linear_size_params,
356277d27096SJiri Pirko struct devlink_resource_size_params *hash_double_size_params,
356377d27096SJiri Pirko struct devlink_resource_size_params *hash_single_size_params)
3564ef3116e5SArkadi Sharshevsky {
3565ef3116e5SArkadi Sharshevsky u32 single_size_min = MLXSW_CORE_RES_GET(mlxsw_core,
3566ef3116e5SArkadi Sharshevsky KVD_SINGLE_MIN_SIZE);
3567ef3116e5SArkadi Sharshevsky u32 double_size_min = MLXSW_CORE_RES_GET(mlxsw_core,
3568ef3116e5SArkadi Sharshevsky KVD_DOUBLE_MIN_SIZE);
3569ef3116e5SArkadi Sharshevsky u32 kvd_size = MLXSW_CORE_RES_GET(mlxsw_core, KVD_SIZE);
3570ef3116e5SArkadi Sharshevsky u32 linear_size_min = 0;
3571ef3116e5SArkadi Sharshevsky
357277d27096SJiri Pirko devlink_resource_size_params_init(kvd_size_params, kvd_size, kvd_size,
357377d27096SJiri Pirko MLXSW_SP_KVD_GRANULARITY,
357477d27096SJiri Pirko DEVLINK_RESOURCE_UNIT_ENTRY);
357577d27096SJiri Pirko devlink_resource_size_params_init(linear_size_params, linear_size_min,
357677d27096SJiri Pirko kvd_size - single_size_min -
357777d27096SJiri Pirko double_size_min,
357877d27096SJiri Pirko MLXSW_SP_KVD_GRANULARITY,
357977d27096SJiri Pirko DEVLINK_RESOURCE_UNIT_ENTRY);
358077d27096SJiri Pirko devlink_resource_size_params_init(hash_double_size_params,
358177d27096SJiri Pirko double_size_min,
358277d27096SJiri Pirko kvd_size - single_size_min -
358377d27096SJiri Pirko linear_size_min,
358477d27096SJiri Pirko MLXSW_SP_KVD_GRANULARITY,
358577d27096SJiri Pirko DEVLINK_RESOURCE_UNIT_ENTRY);
358677d27096SJiri Pirko devlink_resource_size_params_init(hash_single_size_params,
358777d27096SJiri Pirko single_size_min,
358877d27096SJiri Pirko kvd_size - double_size_min -
358977d27096SJiri Pirko linear_size_min,
359077d27096SJiri Pirko MLXSW_SP_KVD_GRANULARITY,
359177d27096SJiri Pirko DEVLINK_RESOURCE_UNIT_ENTRY);
3592ef3116e5SArkadi Sharshevsky }
3593ef3116e5SArkadi Sharshevsky
mlxsw_sp1_resources_kvd_register(struct mlxsw_core * mlxsw_core)3594c3ab4354SJiri Pirko static int mlxsw_sp1_resources_kvd_register(struct mlxsw_core *mlxsw_core)
3595ef3116e5SArkadi Sharshevsky {
3596ef3116e5SArkadi Sharshevsky struct devlink *devlink = priv_to_devlink(mlxsw_core);
359777d27096SJiri Pirko struct devlink_resource_size_params hash_single_size_params;
359877d27096SJiri Pirko struct devlink_resource_size_params hash_double_size_params;
359977d27096SJiri Pirko struct devlink_resource_size_params linear_size_params;
360077d27096SJiri Pirko struct devlink_resource_size_params kvd_size_params;
3601ef3116e5SArkadi Sharshevsky u32 kvd_size, single_size, double_size, linear_size;
3602ef3116e5SArkadi Sharshevsky const struct mlxsw_config_profile *profile;
3603ef3116e5SArkadi Sharshevsky int err;
3604ef3116e5SArkadi Sharshevsky
3605c3ab4354SJiri Pirko profile = &mlxsw_sp1_config_profile;
3606ef3116e5SArkadi Sharshevsky if (!MLXSW_CORE_RES_VALID(mlxsw_core, KVD_SIZE))
3607ef3116e5SArkadi Sharshevsky return -EIO;
3608ef3116e5SArkadi Sharshevsky
360977d27096SJiri Pirko mlxsw_sp_resource_size_params_prepare(mlxsw_core, &kvd_size_params,
361077d27096SJiri Pirko &linear_size_params,
361177d27096SJiri Pirko &hash_double_size_params,
361277d27096SJiri Pirko &hash_single_size_params);
361377d27096SJiri Pirko
3614ef3116e5SArkadi Sharshevsky kvd_size = MLXSW_CORE_RES_GET(mlxsw_core, KVD_SIZE);
361572a4c8c9SJiri Pirko err = devl_resource_register(devlink, MLXSW_SP_RESOURCE_NAME_KVD,
361614530746SDavid Ahern kvd_size, MLXSW_SP_RESOURCE_KVD,
3617ef3116e5SArkadi Sharshevsky DEVLINK_RESOURCE_ID_PARENT_TOP,
3618fc56be47SJiri Pirko &kvd_size_params);
3619ef3116e5SArkadi Sharshevsky if (err)
3620ef3116e5SArkadi Sharshevsky return err;
3621ef3116e5SArkadi Sharshevsky
3622ef3116e5SArkadi Sharshevsky linear_size = profile->kvd_linear_size;
362372a4c8c9SJiri Pirko err = devl_resource_register(devlink, MLXSW_SP_RESOURCE_NAME_KVD_LINEAR,
362414530746SDavid Ahern linear_size,
3625ef3116e5SArkadi Sharshevsky MLXSW_SP_RESOURCE_KVD_LINEAR,
3626ef3116e5SArkadi Sharshevsky MLXSW_SP_RESOURCE_KVD,
3627fc56be47SJiri Pirko &linear_size_params);
3628ef3116e5SArkadi Sharshevsky if (err)
3629ef3116e5SArkadi Sharshevsky return err;
3630ef3116e5SArkadi Sharshevsky
3631ebcff743SJiri Pirko err = mlxsw_sp1_kvdl_resources_register(mlxsw_core);
363251d3c08eSArkadi Sharshevsky if (err)
363351d3c08eSArkadi Sharshevsky return err;
363451d3c08eSArkadi Sharshevsky
3635ef3116e5SArkadi Sharshevsky double_size = kvd_size - linear_size;
3636ef3116e5SArkadi Sharshevsky double_size *= profile->kvd_hash_double_parts;
3637ef3116e5SArkadi Sharshevsky double_size /= profile->kvd_hash_double_parts +
3638ef3116e5SArkadi Sharshevsky profile->kvd_hash_single_parts;
363972779c97SJiri Pirko double_size = rounddown(double_size, MLXSW_SP_KVD_GRANULARITY);
364072a4c8c9SJiri Pirko err = devl_resource_register(devlink, MLXSW_SP_RESOURCE_NAME_KVD_HASH_DOUBLE,
364114530746SDavid Ahern double_size,
3642ef3116e5SArkadi Sharshevsky MLXSW_SP_RESOURCE_KVD_HASH_DOUBLE,
3643ef3116e5SArkadi Sharshevsky MLXSW_SP_RESOURCE_KVD,
3644fc56be47SJiri Pirko &hash_double_size_params);
3645ef3116e5SArkadi Sharshevsky if (err)
3646ef3116e5SArkadi Sharshevsky return err;
3647ef3116e5SArkadi Sharshevsky
3648ef3116e5SArkadi Sharshevsky single_size = kvd_size - double_size - linear_size;
364972a4c8c9SJiri Pirko err = devl_resource_register(devlink, MLXSW_SP_RESOURCE_NAME_KVD_HASH_SINGLE,
365014530746SDavid Ahern single_size,
3651ef3116e5SArkadi Sharshevsky MLXSW_SP_RESOURCE_KVD_HASH_SINGLE,
3652ef3116e5SArkadi Sharshevsky MLXSW_SP_RESOURCE_KVD,
3653fc56be47SJiri Pirko &hash_single_size_params);
3654ef3116e5SArkadi Sharshevsky if (err)
3655ef3116e5SArkadi Sharshevsky return err;
3656ef3116e5SArkadi Sharshevsky
3657ef3116e5SArkadi Sharshevsky return 0;
3658ef3116e5SArkadi Sharshevsky }
3659ef3116e5SArkadi Sharshevsky
mlxsw_sp2_resources_kvd_register(struct mlxsw_core * mlxsw_core)3660b06689ccSAmit Cohen static int mlxsw_sp2_resources_kvd_register(struct mlxsw_core *mlxsw_core)
3661b06689ccSAmit Cohen {
3662b06689ccSAmit Cohen struct devlink *devlink = priv_to_devlink(mlxsw_core);
3663b06689ccSAmit Cohen struct devlink_resource_size_params kvd_size_params;
3664b06689ccSAmit Cohen u32 kvd_size;
3665b06689ccSAmit Cohen
3666b06689ccSAmit Cohen if (!MLXSW_CORE_RES_VALID(mlxsw_core, KVD_SIZE))
3667b06689ccSAmit Cohen return -EIO;
3668b06689ccSAmit Cohen
3669b06689ccSAmit Cohen kvd_size = MLXSW_CORE_RES_GET(mlxsw_core, KVD_SIZE);
3670b06689ccSAmit Cohen devlink_resource_size_params_init(&kvd_size_params, kvd_size, kvd_size,
3671b06689ccSAmit Cohen MLXSW_SP_KVD_GRANULARITY,
3672b06689ccSAmit Cohen DEVLINK_RESOURCE_UNIT_ENTRY);
3673b06689ccSAmit Cohen
367472a4c8c9SJiri Pirko return devl_resource_register(devlink, MLXSW_SP_RESOURCE_NAME_KVD,
3675b06689ccSAmit Cohen kvd_size, MLXSW_SP_RESOURCE_KVD,
3676b06689ccSAmit Cohen DEVLINK_RESOURCE_ID_PARENT_TOP,
3677b06689ccSAmit Cohen &kvd_size_params);
3678b06689ccSAmit Cohen }
3679b06689ccSAmit Cohen
mlxsw_sp_resources_span_register(struct mlxsw_core * mlxsw_core)3680868678c5SDanielle Ratson static int mlxsw_sp_resources_span_register(struct mlxsw_core *mlxsw_core)
3681868678c5SDanielle Ratson {
3682868678c5SDanielle Ratson struct devlink *devlink = priv_to_devlink(mlxsw_core);
3683868678c5SDanielle Ratson struct devlink_resource_size_params span_size_params;
3684868678c5SDanielle Ratson u32 max_span;
3685868678c5SDanielle Ratson
3686868678c5SDanielle Ratson if (!MLXSW_CORE_RES_VALID(mlxsw_core, MAX_SPAN))
3687868678c5SDanielle Ratson return -EIO;
3688868678c5SDanielle Ratson
3689868678c5SDanielle Ratson max_span = MLXSW_CORE_RES_GET(mlxsw_core, MAX_SPAN);
3690868678c5SDanielle Ratson devlink_resource_size_params_init(&span_size_params, max_span, max_span,
3691868678c5SDanielle Ratson 1, DEVLINK_RESOURCE_UNIT_ENTRY);
3692868678c5SDanielle Ratson
369372a4c8c9SJiri Pirko return devl_resource_register(devlink, MLXSW_SP_RESOURCE_NAME_SPAN,
3694868678c5SDanielle Ratson max_span, MLXSW_SP_RESOURCE_SPAN,
3695868678c5SDanielle Ratson DEVLINK_RESOURCE_ID_PARENT_TOP,
3696868678c5SDanielle Ratson &span_size_params);
3697868678c5SDanielle Ratson }
3698868678c5SDanielle Ratson
36991c375ffbSDanielle Ratson static int
mlxsw_sp_resources_rif_mac_profile_register(struct mlxsw_core * mlxsw_core)37001c375ffbSDanielle Ratson mlxsw_sp_resources_rif_mac_profile_register(struct mlxsw_core *mlxsw_core)
37011c375ffbSDanielle Ratson {
37021c375ffbSDanielle Ratson struct devlink *devlink = priv_to_devlink(mlxsw_core);
37031c375ffbSDanielle Ratson struct devlink_resource_size_params size_params;
37041c375ffbSDanielle Ratson u8 max_rif_mac_profiles;
37051c375ffbSDanielle Ratson
37061c375ffbSDanielle Ratson if (!MLXSW_CORE_RES_VALID(mlxsw_core, MAX_RIF_MAC_PROFILES))
3707ce4995bcSDanielle Ratson max_rif_mac_profiles = 1;
3708ce4995bcSDanielle Ratson else
37091c375ffbSDanielle Ratson max_rif_mac_profiles = MLXSW_CORE_RES_GET(mlxsw_core,
37101c375ffbSDanielle Ratson MAX_RIF_MAC_PROFILES);
37111c375ffbSDanielle Ratson devlink_resource_size_params_init(&size_params, max_rif_mac_profiles,
37121c375ffbSDanielle Ratson max_rif_mac_profiles, 1,
37131c375ffbSDanielle Ratson DEVLINK_RESOURCE_UNIT_ENTRY);
37141c375ffbSDanielle Ratson
371572a4c8c9SJiri Pirko return devl_resource_register(devlink,
37161c375ffbSDanielle Ratson "rif_mac_profiles",
37171c375ffbSDanielle Ratson max_rif_mac_profiles,
37181c375ffbSDanielle Ratson MLXSW_SP_RESOURCE_RIF_MAC_PROFILES,
37191c375ffbSDanielle Ratson DEVLINK_RESOURCE_ID_PARENT_TOP,
37201c375ffbSDanielle Ratson &size_params);
37211c375ffbSDanielle Ratson }
37221c375ffbSDanielle Ratson
mlxsw_sp_resources_rifs_register(struct mlxsw_core * mlxsw_core)37234ec2feb2SPetr Machata static int mlxsw_sp_resources_rifs_register(struct mlxsw_core *mlxsw_core)
37244ec2feb2SPetr Machata {
37254ec2feb2SPetr Machata struct devlink *devlink = priv_to_devlink(mlxsw_core);
37264ec2feb2SPetr Machata struct devlink_resource_size_params size_params;
37274ec2feb2SPetr Machata u64 max_rifs;
37284ec2feb2SPetr Machata
37294ec2feb2SPetr Machata if (!MLXSW_CORE_RES_VALID(mlxsw_core, MAX_RIFS))
37304ec2feb2SPetr Machata return -EIO;
37314ec2feb2SPetr Machata
37324ec2feb2SPetr Machata max_rifs = MLXSW_CORE_RES_GET(mlxsw_core, MAX_RIFS);
37334ec2feb2SPetr Machata devlink_resource_size_params_init(&size_params, max_rifs, max_rifs,
37344ec2feb2SPetr Machata 1, DEVLINK_RESOURCE_UNIT_ENTRY);
37354ec2feb2SPetr Machata
373672a4c8c9SJiri Pirko return devl_resource_register(devlink, "rifs", max_rifs,
37374ec2feb2SPetr Machata MLXSW_SP_RESOURCE_RIFS,
37384ec2feb2SPetr Machata DEVLINK_RESOURCE_ID_PARENT_TOP,
37394ec2feb2SPetr Machata &size_params);
37404ec2feb2SPetr Machata }
37414ec2feb2SPetr Machata
374274d6786cSIdo Schimmel static int
mlxsw_sp_resources_port_range_register(struct mlxsw_core * mlxsw_core)374374d6786cSIdo Schimmel mlxsw_sp_resources_port_range_register(struct mlxsw_core *mlxsw_core)
374474d6786cSIdo Schimmel {
374574d6786cSIdo Schimmel struct devlink *devlink = priv_to_devlink(mlxsw_core);
374674d6786cSIdo Schimmel struct devlink_resource_size_params size_params;
374774d6786cSIdo Schimmel u64 max;
374874d6786cSIdo Schimmel
374974d6786cSIdo Schimmel if (!MLXSW_CORE_RES_VALID(mlxsw_core, ACL_MAX_L4_PORT_RANGE))
375074d6786cSIdo Schimmel return -EIO;
375174d6786cSIdo Schimmel
375274d6786cSIdo Schimmel max = MLXSW_CORE_RES_GET(mlxsw_core, ACL_MAX_L4_PORT_RANGE);
375374d6786cSIdo Schimmel devlink_resource_size_params_init(&size_params, max, max, 1,
375474d6786cSIdo Schimmel DEVLINK_RESOURCE_UNIT_ENTRY);
375574d6786cSIdo Schimmel
375674d6786cSIdo Schimmel return devl_resource_register(devlink, "port_range_registers", max,
375774d6786cSIdo Schimmel MLXSW_SP_RESOURCE_PORT_RANGE_REGISTERS,
375874d6786cSIdo Schimmel DEVLINK_RESOURCE_ID_PARENT_TOP,
375974d6786cSIdo Schimmel &size_params);
376074d6786cSIdo Schimmel }
376174d6786cSIdo Schimmel
mlxsw_sp1_resources_register(struct mlxsw_core * mlxsw_core)3762c3ab4354SJiri Pirko static int mlxsw_sp1_resources_register(struct mlxsw_core *mlxsw_core)
3763c3ab4354SJiri Pirko {
3764868678c5SDanielle Ratson int err;
3765868678c5SDanielle Ratson
3766868678c5SDanielle Ratson err = mlxsw_sp1_resources_kvd_register(mlxsw_core);
3767868678c5SDanielle Ratson if (err)
3768868678c5SDanielle Ratson return err;
3769868678c5SDanielle Ratson
3770868678c5SDanielle Ratson err = mlxsw_sp_resources_span_register(mlxsw_core);
3771868678c5SDanielle Ratson if (err)
3772868678c5SDanielle Ratson goto err_resources_span_register;
3773868678c5SDanielle Ratson
3774d53cdbb8SJiri Pirko err = mlxsw_sp_counter_resources_register(mlxsw_core);
3775d53cdbb8SJiri Pirko if (err)
3776d53cdbb8SJiri Pirko goto err_resources_counter_register;
3777d53cdbb8SJiri Pirko
3778bf038f03SIdo Schimmel err = mlxsw_sp_policer_resources_register(mlxsw_core);
3779bf038f03SIdo Schimmel if (err)
37801c375ffbSDanielle Ratson goto err_policer_resources_register;
37811c375ffbSDanielle Ratson
37821c375ffbSDanielle Ratson err = mlxsw_sp_resources_rif_mac_profile_register(mlxsw_core);
37831c375ffbSDanielle Ratson if (err)
37841c375ffbSDanielle Ratson goto err_resources_rif_mac_profile_register;
3785bf038f03SIdo Schimmel
37864ec2feb2SPetr Machata err = mlxsw_sp_resources_rifs_register(mlxsw_core);
37874ec2feb2SPetr Machata if (err)
37884ec2feb2SPetr Machata goto err_resources_rifs_register;
37894ec2feb2SPetr Machata
379074d6786cSIdo Schimmel err = mlxsw_sp_resources_port_range_register(mlxsw_core);
379174d6786cSIdo Schimmel if (err)
379274d6786cSIdo Schimmel goto err_resources_port_range_register;
379374d6786cSIdo Schimmel
3794868678c5SDanielle Ratson return 0;
3795868678c5SDanielle Ratson
379674d6786cSIdo Schimmel err_resources_port_range_register:
37974ec2feb2SPetr Machata err_resources_rifs_register:
37981c375ffbSDanielle Ratson err_resources_rif_mac_profile_register:
37991c375ffbSDanielle Ratson err_policer_resources_register:
3800d53cdbb8SJiri Pirko err_resources_counter_register:
3801868678c5SDanielle Ratson err_resources_span_register:
380272a4c8c9SJiri Pirko devl_resources_unregister(priv_to_devlink(mlxsw_core));
3803868678c5SDanielle Ratson return err;
3804c3ab4354SJiri Pirko }
3805c3ab4354SJiri Pirko
mlxsw_sp2_resources_register(struct mlxsw_core * mlxsw_core)3806c3ab4354SJiri Pirko static int mlxsw_sp2_resources_register(struct mlxsw_core *mlxsw_core)
3807c3ab4354SJiri Pirko {
3808868678c5SDanielle Ratson int err;
3809868678c5SDanielle Ratson
3810868678c5SDanielle Ratson err = mlxsw_sp2_resources_kvd_register(mlxsw_core);
3811868678c5SDanielle Ratson if (err)
3812868678c5SDanielle Ratson return err;
3813868678c5SDanielle Ratson
3814868678c5SDanielle Ratson err = mlxsw_sp_resources_span_register(mlxsw_core);
3815868678c5SDanielle Ratson if (err)
3816868678c5SDanielle Ratson goto err_resources_span_register;
3817868678c5SDanielle Ratson
3818d53cdbb8SJiri Pirko err = mlxsw_sp_counter_resources_register(mlxsw_core);
3819d53cdbb8SJiri Pirko if (err)
3820d53cdbb8SJiri Pirko goto err_resources_counter_register;
3821d53cdbb8SJiri Pirko
3822bf038f03SIdo Schimmel err = mlxsw_sp_policer_resources_register(mlxsw_core);
3823bf038f03SIdo Schimmel if (err)
38241c375ffbSDanielle Ratson goto err_policer_resources_register;
38251c375ffbSDanielle Ratson
38261c375ffbSDanielle Ratson err = mlxsw_sp_resources_rif_mac_profile_register(mlxsw_core);
38271c375ffbSDanielle Ratson if (err)
38281c375ffbSDanielle Ratson goto err_resources_rif_mac_profile_register;
3829bf038f03SIdo Schimmel
38304ec2feb2SPetr Machata err = mlxsw_sp_resources_rifs_register(mlxsw_core);
38314ec2feb2SPetr Machata if (err)
38324ec2feb2SPetr Machata goto err_resources_rifs_register;
38334ec2feb2SPetr Machata
383474d6786cSIdo Schimmel err = mlxsw_sp_resources_port_range_register(mlxsw_core);
383574d6786cSIdo Schimmel if (err)
383674d6786cSIdo Schimmel goto err_resources_port_range_register;
383774d6786cSIdo Schimmel
3838868678c5SDanielle Ratson return 0;
3839868678c5SDanielle Ratson
384074d6786cSIdo Schimmel err_resources_port_range_register:
38414ec2feb2SPetr Machata err_resources_rifs_register:
38421c375ffbSDanielle Ratson err_resources_rif_mac_profile_register:
38431c375ffbSDanielle Ratson err_policer_resources_register:
3844d53cdbb8SJiri Pirko err_resources_counter_register:
3845868678c5SDanielle Ratson err_resources_span_register:
384672a4c8c9SJiri Pirko devl_resources_unregister(priv_to_devlink(mlxsw_core));
3847868678c5SDanielle Ratson return err;
3848c3ab4354SJiri Pirko }
3849c3ab4354SJiri Pirko
mlxsw_sp_kvd_sizes_get(struct mlxsw_core * mlxsw_core,const struct mlxsw_config_profile * profile,u64 * p_single_size,u64 * p_double_size,u64 * p_linear_size)3850e21d21caSArkadi Sharshevsky static int mlxsw_sp_kvd_sizes_get(struct mlxsw_core *mlxsw_core,
3851e21d21caSArkadi Sharshevsky const struct mlxsw_config_profile *profile,
3852e21d21caSArkadi Sharshevsky u64 *p_single_size, u64 *p_double_size,
3853e21d21caSArkadi Sharshevsky u64 *p_linear_size)
3854e21d21caSArkadi Sharshevsky {
3855e21d21caSArkadi Sharshevsky struct devlink *devlink = priv_to_devlink(mlxsw_core);
3856e21d21caSArkadi Sharshevsky u32 double_size;
3857e21d21caSArkadi Sharshevsky int err;
3858e21d21caSArkadi Sharshevsky
3859e21d21caSArkadi Sharshevsky if (!MLXSW_CORE_RES_VALID(mlxsw_core, KVD_SINGLE_MIN_SIZE) ||
3860110d2d21SJiri Pirko !MLXSW_CORE_RES_VALID(mlxsw_core, KVD_DOUBLE_MIN_SIZE))
3861e21d21caSArkadi Sharshevsky return -EIO;
3862e21d21caSArkadi Sharshevsky
3863e21d21caSArkadi Sharshevsky /* The hash part is what left of the kvd without the
3864e21d21caSArkadi Sharshevsky * linear part. It is split to the single size and
3865e21d21caSArkadi Sharshevsky * double size by the parts ratio from the profile.
3866e21d21caSArkadi Sharshevsky * Both sizes must be a multiplications of the
3867e21d21caSArkadi Sharshevsky * granularity from the profile. In case the user
3868e21d21caSArkadi Sharshevsky * provided the sizes they are obtained via devlink.
3869e21d21caSArkadi Sharshevsky */
387072a4c8c9SJiri Pirko err = devl_resource_size_get(devlink,
3871e21d21caSArkadi Sharshevsky MLXSW_SP_RESOURCE_KVD_LINEAR,
3872e21d21caSArkadi Sharshevsky p_linear_size);
3873e21d21caSArkadi Sharshevsky if (err)
3874e21d21caSArkadi Sharshevsky *p_linear_size = profile->kvd_linear_size;
3875e21d21caSArkadi Sharshevsky
387672a4c8c9SJiri Pirko err = devl_resource_size_get(devlink,
3877e21d21caSArkadi Sharshevsky MLXSW_SP_RESOURCE_KVD_HASH_DOUBLE,
3878e21d21caSArkadi Sharshevsky p_double_size);
3879e21d21caSArkadi Sharshevsky if (err) {
3880e21d21caSArkadi Sharshevsky double_size = MLXSW_CORE_RES_GET(mlxsw_core, KVD_SIZE) -
3881e21d21caSArkadi Sharshevsky *p_linear_size;
3882e21d21caSArkadi Sharshevsky double_size *= profile->kvd_hash_double_parts;
3883e21d21caSArkadi Sharshevsky double_size /= profile->kvd_hash_double_parts +
3884e21d21caSArkadi Sharshevsky profile->kvd_hash_single_parts;
3885e21d21caSArkadi Sharshevsky *p_double_size = rounddown(double_size,
388672779c97SJiri Pirko MLXSW_SP_KVD_GRANULARITY);
3887e21d21caSArkadi Sharshevsky }
3888e21d21caSArkadi Sharshevsky
388972a4c8c9SJiri Pirko err = devl_resource_size_get(devlink,
3890e21d21caSArkadi Sharshevsky MLXSW_SP_RESOURCE_KVD_HASH_SINGLE,
3891e21d21caSArkadi Sharshevsky p_single_size);
3892e21d21caSArkadi Sharshevsky if (err)
3893e21d21caSArkadi Sharshevsky *p_single_size = MLXSW_CORE_RES_GET(mlxsw_core, KVD_SIZE) -
3894e21d21caSArkadi Sharshevsky *p_double_size - *p_linear_size;
3895e21d21caSArkadi Sharshevsky
3896e21d21caSArkadi Sharshevsky /* Check results are legal. */
3897e21d21caSArkadi Sharshevsky if (*p_single_size < MLXSW_CORE_RES_GET(mlxsw_core, KVD_SINGLE_MIN_SIZE) ||
3898e21d21caSArkadi Sharshevsky *p_double_size < MLXSW_CORE_RES_GET(mlxsw_core, KVD_DOUBLE_MIN_SIZE) ||
3899e21d21caSArkadi Sharshevsky MLXSW_CORE_RES_GET(mlxsw_core, KVD_SIZE) < *p_linear_size)
3900e21d21caSArkadi Sharshevsky return -EIO;
3901e21d21caSArkadi Sharshevsky
3902e21d21caSArkadi Sharshevsky return 0;
3903e21d21caSArkadi Sharshevsky }
3904e21d21caSArkadi Sharshevsky
mlxsw_sp_ptp_transmitted(struct mlxsw_core * mlxsw_core,struct sk_buff * skb,u16 local_port)39050714256cSPetr Machata static void mlxsw_sp_ptp_transmitted(struct mlxsw_core *mlxsw_core,
3906c934757dSAmit Cohen struct sk_buff *skb, u16 local_port)
39070714256cSPetr Machata {
39080714256cSPetr Machata struct mlxsw_sp *mlxsw_sp = mlxsw_core_driver_priv(mlxsw_core);
39090714256cSPetr Machata
39100714256cSPetr Machata skb_pull(skb, MLXSW_TXHDR_LEN);
39110714256cSPetr Machata mlxsw_sp->ptp_ops->transmitted(mlxsw_sp, skb, local_port);
39120714256cSPetr Machata }
39130714256cSPetr Machata
3914c3ab4354SJiri Pirko static struct mlxsw_driver mlxsw_sp1_driver = {
3915c3ab4354SJiri Pirko .kind = mlxsw_sp1_driver_name,
391656ade8feSJiri Pirko .priv_size = sizeof(struct mlxsw_sp),
3917b79cb787SJiri Pirko .fw_req_rev = &mlxsw_sp1_fw_rev,
3918b79cb787SJiri Pirko .fw_filename = MLXSW_SP1_FW_FILENAME,
3919c3ab4354SJiri Pirko .init = mlxsw_sp1_init,
392056ade8feSJiri Pirko .fini = mlxsw_sp_fini,
392118f1e70cSIdo Schimmel .port_split = mlxsw_sp_port_split,
392218f1e70cSIdo Schimmel .port_unsplit = mlxsw_sp_port_unsplit,
39230f433fa0SJiri Pirko .sb_pool_get = mlxsw_sp_sb_pool_get,
39240f433fa0SJiri Pirko .sb_pool_set = mlxsw_sp_sb_pool_set,
39250f433fa0SJiri Pirko .sb_port_pool_get = mlxsw_sp_sb_port_pool_get,
39260f433fa0SJiri Pirko .sb_port_pool_set = mlxsw_sp_sb_port_pool_set,
39270f433fa0SJiri Pirko .sb_tc_pool_bind_get = mlxsw_sp_sb_tc_pool_bind_get,
39280f433fa0SJiri Pirko .sb_tc_pool_bind_set = mlxsw_sp_sb_tc_pool_bind_set,
39292d0ed39fSJiri Pirko .sb_occ_snapshot = mlxsw_sp_sb_occ_snapshot,
39302d0ed39fSJiri Pirko .sb_occ_max_clear = mlxsw_sp_sb_occ_max_clear,
39312d0ed39fSJiri Pirko .sb_occ_port_pool_get = mlxsw_sp_sb_occ_port_pool_get,
39322d0ed39fSJiri Pirko .sb_occ_tc_port_bind_get = mlxsw_sp_sb_occ_tc_port_bind_get,
3933b5ce611fSIdo Schimmel .trap_init = mlxsw_sp_trap_init,
3934b5ce611fSIdo Schimmel .trap_fini = mlxsw_sp_trap_fini,
3935b5ce611fSIdo Schimmel .trap_action_set = mlxsw_sp_trap_action_set,
3936b5ce611fSIdo Schimmel .trap_group_init = mlxsw_sp_trap_group_init,
393739defcbbSIdo Schimmel .trap_group_set = mlxsw_sp_trap_group_set,
393813f2e64bSIdo Schimmel .trap_policer_init = mlxsw_sp_trap_policer_init,
393913f2e64bSIdo Schimmel .trap_policer_fini = mlxsw_sp_trap_policer_fini,
394013f2e64bSIdo Schimmel .trap_policer_set = mlxsw_sp_trap_policer_set,
394113f2e64bSIdo Schimmel .trap_policer_counter_get = mlxsw_sp_trap_policer_counter_get,
394256ade8feSJiri Pirko .txhdr_construct = mlxsw_sp_txhdr_construct,
3943c3ab4354SJiri Pirko .resources_register = mlxsw_sp1_resources_register,
3944e21d21caSArkadi Sharshevsky .kvd_sizes_get = mlxsw_sp_kvd_sizes_get,
39450714256cSPetr Machata .ptp_transmitted = mlxsw_sp_ptp_transmitted,
394656ade8feSJiri Pirko .txhdr_len = MLXSW_TXHDR_LEN,
3947c3ab4354SJiri Pirko .profile = &mlxsw_sp1_config_profile,
394842823208SDanielle Ratson .sdq_supports_cqe_v2 = false,
3949c3ab4354SJiri Pirko };
3950c3ab4354SJiri Pirko
3951c3ab4354SJiri Pirko static struct mlxsw_driver mlxsw_sp2_driver = {
3952c3ab4354SJiri Pirko .kind = mlxsw_sp2_driver_name,
3953c3ab4354SJiri Pirko .priv_size = sizeof(struct mlxsw_sp),
3954b79cb787SJiri Pirko .fw_req_rev = &mlxsw_sp2_fw_rev,
3955b79cb787SJiri Pirko .fw_filename = MLXSW_SP2_FW_FILENAME,
3956c3ab4354SJiri Pirko .init = mlxsw_sp2_init,
3957c3ab4354SJiri Pirko .fini = mlxsw_sp_fini,
3958c3ab4354SJiri Pirko .port_split = mlxsw_sp_port_split,
3959c3ab4354SJiri Pirko .port_unsplit = mlxsw_sp_port_unsplit,
396045bf3b72SJiri Pirko .ports_remove_selected = mlxsw_sp_ports_remove_selected,
3961c3ab4354SJiri Pirko .sb_pool_get = mlxsw_sp_sb_pool_get,
3962c3ab4354SJiri Pirko .sb_pool_set = mlxsw_sp_sb_pool_set,
3963c3ab4354SJiri Pirko .sb_port_pool_get = mlxsw_sp_sb_port_pool_get,
3964c3ab4354SJiri Pirko .sb_port_pool_set = mlxsw_sp_sb_port_pool_set,
3965c3ab4354SJiri Pirko .sb_tc_pool_bind_get = mlxsw_sp_sb_tc_pool_bind_get,
3966c3ab4354SJiri Pirko .sb_tc_pool_bind_set = mlxsw_sp_sb_tc_pool_bind_set,
3967c3ab4354SJiri Pirko .sb_occ_snapshot = mlxsw_sp_sb_occ_snapshot,
3968c3ab4354SJiri Pirko .sb_occ_max_clear = mlxsw_sp_sb_occ_max_clear,
3969c3ab4354SJiri Pirko .sb_occ_port_pool_get = mlxsw_sp_sb_occ_port_pool_get,
3970c3ab4354SJiri Pirko .sb_occ_tc_port_bind_get = mlxsw_sp_sb_occ_tc_port_bind_get,
3971b5ce611fSIdo Schimmel .trap_init = mlxsw_sp_trap_init,
3972b5ce611fSIdo Schimmel .trap_fini = mlxsw_sp_trap_fini,
3973b5ce611fSIdo Schimmel .trap_action_set = mlxsw_sp_trap_action_set,
3974b5ce611fSIdo Schimmel .trap_group_init = mlxsw_sp_trap_group_init,
397539defcbbSIdo Schimmel .trap_group_set = mlxsw_sp_trap_group_set,
397613f2e64bSIdo Schimmel .trap_policer_init = mlxsw_sp_trap_policer_init,
397713f2e64bSIdo Schimmel .trap_policer_fini = mlxsw_sp_trap_policer_fini,
397813f2e64bSIdo Schimmel .trap_policer_set = mlxsw_sp_trap_policer_set,
397913f2e64bSIdo Schimmel .trap_policer_counter_get = mlxsw_sp_trap_policer_counter_get,
3980c3ab4354SJiri Pirko .txhdr_construct = mlxsw_sp_txhdr_construct,
3981c3ab4354SJiri Pirko .resources_register = mlxsw_sp2_resources_register,
39820714256cSPetr Machata .ptp_transmitted = mlxsw_sp_ptp_transmitted,
3983c3ab4354SJiri Pirko .txhdr_len = MLXSW_TXHDR_LEN,
3984c3ab4354SJiri Pirko .profile = &mlxsw_sp2_config_profile,
398542823208SDanielle Ratson .sdq_supports_cqe_v2 = true,
398656ade8feSJiri Pirko };
398756ade8feSJiri Pirko
3988da382875SJiri Pirko static struct mlxsw_driver mlxsw_sp3_driver = {
3989da382875SJiri Pirko .kind = mlxsw_sp3_driver_name,
3990da382875SJiri Pirko .priv_size = sizeof(struct mlxsw_sp),
3991b79cb787SJiri Pirko .fw_req_rev = &mlxsw_sp3_fw_rev,
3992b79cb787SJiri Pirko .fw_filename = MLXSW_SP3_FW_FILENAME,
3993d58c35caSIdo Schimmel .init = mlxsw_sp3_init,
3994da382875SJiri Pirko .fini = mlxsw_sp_fini,
3995da382875SJiri Pirko .port_split = mlxsw_sp_port_split,
3996da382875SJiri Pirko .port_unsplit = mlxsw_sp_port_unsplit,
399745bf3b72SJiri Pirko .ports_remove_selected = mlxsw_sp_ports_remove_selected,
3998da382875SJiri Pirko .sb_pool_get = mlxsw_sp_sb_pool_get,
3999da382875SJiri Pirko .sb_pool_set = mlxsw_sp_sb_pool_set,
4000da382875SJiri Pirko .sb_port_pool_get = mlxsw_sp_sb_port_pool_get,
4001da382875SJiri Pirko .sb_port_pool_set = mlxsw_sp_sb_port_pool_set,
4002da382875SJiri Pirko .sb_tc_pool_bind_get = mlxsw_sp_sb_tc_pool_bind_get,
4003da382875SJiri Pirko .sb_tc_pool_bind_set = mlxsw_sp_sb_tc_pool_bind_set,
4004da382875SJiri Pirko .sb_occ_snapshot = mlxsw_sp_sb_occ_snapshot,
4005da382875SJiri Pirko .sb_occ_max_clear = mlxsw_sp_sb_occ_max_clear,
4006da382875SJiri Pirko .sb_occ_port_pool_get = mlxsw_sp_sb_occ_port_pool_get,
4007da382875SJiri Pirko .sb_occ_tc_port_bind_get = mlxsw_sp_sb_occ_tc_port_bind_get,
4008b5ce611fSIdo Schimmel .trap_init = mlxsw_sp_trap_init,
4009b5ce611fSIdo Schimmel .trap_fini = mlxsw_sp_trap_fini,
4010b5ce611fSIdo Schimmel .trap_action_set = mlxsw_sp_trap_action_set,
4011b5ce611fSIdo Schimmel .trap_group_init = mlxsw_sp_trap_group_init,
401239defcbbSIdo Schimmel .trap_group_set = mlxsw_sp_trap_group_set,
401313f2e64bSIdo Schimmel .trap_policer_init = mlxsw_sp_trap_policer_init,
401413f2e64bSIdo Schimmel .trap_policer_fini = mlxsw_sp_trap_policer_fini,
401513f2e64bSIdo Schimmel .trap_policer_set = mlxsw_sp_trap_policer_set,
401613f2e64bSIdo Schimmel .trap_policer_counter_get = mlxsw_sp_trap_policer_counter_get,
4017da382875SJiri Pirko .txhdr_construct = mlxsw_sp_txhdr_construct,
4018da382875SJiri Pirko .resources_register = mlxsw_sp2_resources_register,
4019da382875SJiri Pirko .ptp_transmitted = mlxsw_sp_ptp_transmitted,
4020da382875SJiri Pirko .txhdr_len = MLXSW_TXHDR_LEN,
4021da382875SJiri Pirko .profile = &mlxsw_sp2_config_profile,
402242823208SDanielle Ratson .sdq_supports_cqe_v2 = true,
4023da382875SJiri Pirko };
4024da382875SJiri Pirko
402547354021SAmit Cohen static struct mlxsw_driver mlxsw_sp4_driver = {
402647354021SAmit Cohen .kind = mlxsw_sp4_driver_name,
402747354021SAmit Cohen .priv_size = sizeof(struct mlxsw_sp),
402847354021SAmit Cohen .init = mlxsw_sp4_init,
402947354021SAmit Cohen .fini = mlxsw_sp_fini,
403047354021SAmit Cohen .port_split = mlxsw_sp_port_split,
403147354021SAmit Cohen .port_unsplit = mlxsw_sp_port_unsplit,
403245bf3b72SJiri Pirko .ports_remove_selected = mlxsw_sp_ports_remove_selected,
403347354021SAmit Cohen .sb_pool_get = mlxsw_sp_sb_pool_get,
403447354021SAmit Cohen .sb_pool_set = mlxsw_sp_sb_pool_set,
403547354021SAmit Cohen .sb_port_pool_get = mlxsw_sp_sb_port_pool_get,
403647354021SAmit Cohen .sb_port_pool_set = mlxsw_sp_sb_port_pool_set,
403747354021SAmit Cohen .sb_tc_pool_bind_get = mlxsw_sp_sb_tc_pool_bind_get,
403847354021SAmit Cohen .sb_tc_pool_bind_set = mlxsw_sp_sb_tc_pool_bind_set,
403947354021SAmit Cohen .sb_occ_snapshot = mlxsw_sp_sb_occ_snapshot,
404047354021SAmit Cohen .sb_occ_max_clear = mlxsw_sp_sb_occ_max_clear,
404147354021SAmit Cohen .sb_occ_port_pool_get = mlxsw_sp_sb_occ_port_pool_get,
404247354021SAmit Cohen .sb_occ_tc_port_bind_get = mlxsw_sp_sb_occ_tc_port_bind_get,
404347354021SAmit Cohen .trap_init = mlxsw_sp_trap_init,
404447354021SAmit Cohen .trap_fini = mlxsw_sp_trap_fini,
404547354021SAmit Cohen .trap_action_set = mlxsw_sp_trap_action_set,
404647354021SAmit Cohen .trap_group_init = mlxsw_sp_trap_group_init,
404747354021SAmit Cohen .trap_group_set = mlxsw_sp_trap_group_set,
404847354021SAmit Cohen .trap_policer_init = mlxsw_sp_trap_policer_init,
404947354021SAmit Cohen .trap_policer_fini = mlxsw_sp_trap_policer_fini,
405047354021SAmit Cohen .trap_policer_set = mlxsw_sp_trap_policer_set,
405147354021SAmit Cohen .trap_policer_counter_get = mlxsw_sp_trap_policer_counter_get,
405247354021SAmit Cohen .txhdr_construct = mlxsw_sp_txhdr_construct,
405347354021SAmit Cohen .resources_register = mlxsw_sp2_resources_register,
405447354021SAmit Cohen .ptp_transmitted = mlxsw_sp_ptp_transmitted,
405547354021SAmit Cohen .txhdr_len = MLXSW_TXHDR_LEN,
4056c503d8aeSAmit Cohen .profile = &mlxsw_sp4_config_profile,
405742823208SDanielle Ratson .sdq_supports_cqe_v2 = true,
405847354021SAmit Cohen };
405947354021SAmit Cohen
mlxsw_sp_port_dev_check(const struct net_device * dev)406022a67766SJiri Pirko bool mlxsw_sp_port_dev_check(const struct net_device *dev)
40617ce856aaSJiri Pirko {
40627ce856aaSJiri Pirko return dev->netdev_ops == &mlxsw_sp_port_netdev_ops;
40637ce856aaSJiri Pirko }
40647ce856aaSJiri Pirko
mlxsw_sp_lower_dev_walk(struct net_device * lower_dev,struct netdev_nested_priv * priv)4065eff74233STaehee Yoo static int mlxsw_sp_lower_dev_walk(struct net_device *lower_dev,
4066eff74233STaehee Yoo struct netdev_nested_priv *priv)
4067dd82364cSDavid Ahern {
4068dd82364cSDavid Ahern int ret = 0;
4069dd82364cSDavid Ahern
4070dd82364cSDavid Ahern if (mlxsw_sp_port_dev_check(lower_dev)) {
4071eff74233STaehee Yoo priv->data = (void *)netdev_priv(lower_dev);
4072dd82364cSDavid Ahern ret = 1;
4073dd82364cSDavid Ahern }
4074dd82364cSDavid Ahern
4075dd82364cSDavid Ahern return ret;
4076dd82364cSDavid Ahern }
4077dd82364cSDavid Ahern
mlxsw_sp_port_dev_lower_find(struct net_device * dev)4078c57529e1SIdo Schimmel struct mlxsw_sp_port *mlxsw_sp_port_dev_lower_find(struct net_device *dev)
40797ce856aaSJiri Pirko {
4080eff74233STaehee Yoo struct netdev_nested_priv priv = {
4081eff74233STaehee Yoo .data = NULL,
4082eff74233STaehee Yoo };
40837ce856aaSJiri Pirko
40847ce856aaSJiri Pirko if (mlxsw_sp_port_dev_check(dev))
40857ce856aaSJiri Pirko return netdev_priv(dev);
40867ce856aaSJiri Pirko
4087eff74233STaehee Yoo netdev_walk_all_lower_dev(dev, mlxsw_sp_lower_dev_walk, &priv);
4088dd82364cSDavid Ahern
4089eff74233STaehee Yoo return (struct mlxsw_sp_port *)priv.data;
40907ce856aaSJiri Pirko }
40917ce856aaSJiri Pirko
mlxsw_sp_lower_get(struct net_device * dev)40924724ba56SIdo Schimmel struct mlxsw_sp *mlxsw_sp_lower_get(struct net_device *dev)
40937ce856aaSJiri Pirko {
40947ce856aaSJiri Pirko struct mlxsw_sp_port *mlxsw_sp_port;
40957ce856aaSJiri Pirko
40967ce856aaSJiri Pirko mlxsw_sp_port = mlxsw_sp_port_dev_lower_find(dev);
40977ce856aaSJiri Pirko return mlxsw_sp_port ? mlxsw_sp_port->mlxsw_sp : NULL;
40987ce856aaSJiri Pirko }
40997ce856aaSJiri Pirko
mlxsw_sp_port_dev_lower_find_rcu(struct net_device * dev)4100af061378SArkadi Sharshevsky struct mlxsw_sp_port *mlxsw_sp_port_dev_lower_find_rcu(struct net_device *dev)
41017ce856aaSJiri Pirko {
4102eff74233STaehee Yoo struct netdev_nested_priv priv = {
4103eff74233STaehee Yoo .data = NULL,
4104eff74233STaehee Yoo };
41057ce856aaSJiri Pirko
41067ce856aaSJiri Pirko if (mlxsw_sp_port_dev_check(dev))
41077ce856aaSJiri Pirko return netdev_priv(dev);
41087ce856aaSJiri Pirko
41091182e536SJiri Pirko netdev_walk_all_lower_dev_rcu(dev, mlxsw_sp_lower_dev_walk,
4110eff74233STaehee Yoo &priv);
4111dd82364cSDavid Ahern
4112eff74233STaehee Yoo return (struct mlxsw_sp_port *)priv.data;
41137ce856aaSJiri Pirko }
41147ce856aaSJiri Pirko
mlxsw_sp_parsing_depth_inc(struct mlxsw_sp * mlxsw_sp)41152d91f080SAmit Cohen int mlxsw_sp_parsing_depth_inc(struct mlxsw_sp *mlxsw_sp)
41162d91f080SAmit Cohen {
41172d91f080SAmit Cohen char mprs_pl[MLXSW_REG_MPRS_LEN];
41182d91f080SAmit Cohen int err = 0;
41192d91f080SAmit Cohen
41202d91f080SAmit Cohen mutex_lock(&mlxsw_sp->parsing.lock);
41212d91f080SAmit Cohen
41222d91f080SAmit Cohen if (refcount_inc_not_zero(&mlxsw_sp->parsing.parsing_depth_ref))
41232d91f080SAmit Cohen goto out_unlock;
41242d91f080SAmit Cohen
41252d91f080SAmit Cohen mlxsw_reg_mprs_pack(mprs_pl, MLXSW_SP_INCREASED_PARSING_DEPTH,
41262d91f080SAmit Cohen mlxsw_sp->parsing.vxlan_udp_dport);
41272d91f080SAmit Cohen err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(mprs), mprs_pl);
41282d91f080SAmit Cohen if (err)
41292d91f080SAmit Cohen goto out_unlock;
41302d91f080SAmit Cohen
41312d91f080SAmit Cohen mlxsw_sp->parsing.parsing_depth = MLXSW_SP_INCREASED_PARSING_DEPTH;
41322d91f080SAmit Cohen refcount_set(&mlxsw_sp->parsing.parsing_depth_ref, 1);
41332d91f080SAmit Cohen
41342d91f080SAmit Cohen out_unlock:
41352d91f080SAmit Cohen mutex_unlock(&mlxsw_sp->parsing.lock);
41362d91f080SAmit Cohen return err;
41372d91f080SAmit Cohen }
41382d91f080SAmit Cohen
mlxsw_sp_parsing_depth_dec(struct mlxsw_sp * mlxsw_sp)41392d91f080SAmit Cohen void mlxsw_sp_parsing_depth_dec(struct mlxsw_sp *mlxsw_sp)
41402d91f080SAmit Cohen {
41412d91f080SAmit Cohen char mprs_pl[MLXSW_REG_MPRS_LEN];
41422d91f080SAmit Cohen
41432d91f080SAmit Cohen mutex_lock(&mlxsw_sp->parsing.lock);
41442d91f080SAmit Cohen
41452d91f080SAmit Cohen if (!refcount_dec_and_test(&mlxsw_sp->parsing.parsing_depth_ref))
41462d91f080SAmit Cohen goto out_unlock;
41472d91f080SAmit Cohen
41482d91f080SAmit Cohen mlxsw_reg_mprs_pack(mprs_pl, MLXSW_SP_DEFAULT_PARSING_DEPTH,
41492d91f080SAmit Cohen mlxsw_sp->parsing.vxlan_udp_dport);
41502d91f080SAmit Cohen mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(mprs), mprs_pl);
41512d91f080SAmit Cohen mlxsw_sp->parsing.parsing_depth = MLXSW_SP_DEFAULT_PARSING_DEPTH;
41522d91f080SAmit Cohen
41532d91f080SAmit Cohen out_unlock:
41542d91f080SAmit Cohen mutex_unlock(&mlxsw_sp->parsing.lock);
41552d91f080SAmit Cohen }
41562d91f080SAmit Cohen
mlxsw_sp_parsing_vxlan_udp_dport_set(struct mlxsw_sp * mlxsw_sp,__be16 udp_dport)41572d91f080SAmit Cohen int mlxsw_sp_parsing_vxlan_udp_dport_set(struct mlxsw_sp *mlxsw_sp,
41582d91f080SAmit Cohen __be16 udp_dport)
41592d91f080SAmit Cohen {
41602d91f080SAmit Cohen char mprs_pl[MLXSW_REG_MPRS_LEN];
41612d91f080SAmit Cohen int err;
41622d91f080SAmit Cohen
41632d91f080SAmit Cohen mutex_lock(&mlxsw_sp->parsing.lock);
41642d91f080SAmit Cohen
41652d91f080SAmit Cohen mlxsw_reg_mprs_pack(mprs_pl, mlxsw_sp->parsing.parsing_depth,
41662d91f080SAmit Cohen be16_to_cpu(udp_dport));
41672d91f080SAmit Cohen err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(mprs), mprs_pl);
41682d91f080SAmit Cohen if (err)
41692d91f080SAmit Cohen goto out_unlock;
41702d91f080SAmit Cohen
41712d91f080SAmit Cohen mlxsw_sp->parsing.vxlan_udp_dport = be16_to_cpu(udp_dport);
41722d91f080SAmit Cohen
41732d91f080SAmit Cohen out_unlock:
41742d91f080SAmit Cohen mutex_unlock(&mlxsw_sp->parsing.lock);
41752d91f080SAmit Cohen return err;
41762d91f080SAmit Cohen }
41772d91f080SAmit Cohen
4178be2d6f42SIdo Schimmel static void
mlxsw_sp_port_lag_uppers_cleanup(struct mlxsw_sp_port * mlxsw_sp_port,struct net_device * lag_dev)4179be2d6f42SIdo Schimmel mlxsw_sp_port_lag_uppers_cleanup(struct mlxsw_sp_port *mlxsw_sp_port,
4180be2d6f42SIdo Schimmel struct net_device *lag_dev)
4181be2d6f42SIdo Schimmel {
4182be2d6f42SIdo Schimmel struct net_device *br_dev = netdev_master_upper_dev_get(lag_dev);
4183be2d6f42SIdo Schimmel struct net_device *upper_dev;
4184be2d6f42SIdo Schimmel struct list_head *iter;
4185be2d6f42SIdo Schimmel
4186be2d6f42SIdo Schimmel if (netif_is_bridge_port(lag_dev))
4187be2d6f42SIdo Schimmel mlxsw_sp_port_bridge_leave(mlxsw_sp_port, lag_dev, br_dev);
4188be2d6f42SIdo Schimmel
4189be2d6f42SIdo Schimmel netdev_for_each_upper_dev_rcu(lag_dev, upper_dev, iter) {
4190be2d6f42SIdo Schimmel if (!netif_is_bridge_port(upper_dev))
4191be2d6f42SIdo Schimmel continue;
4192be2d6f42SIdo Schimmel br_dev = netdev_master_upper_dev_get(upper_dev);
4193be2d6f42SIdo Schimmel mlxsw_sp_port_bridge_leave(mlxsw_sp_port, upper_dev, br_dev);
4194be2d6f42SIdo Schimmel }
4195be2d6f42SIdo Schimmel }
4196be2d6f42SIdo Schimmel
mlxsw_sp_lag_create(struct mlxsw_sp * mlxsw_sp,u16 lag_id)41970d65fc13SJiri Pirko static int mlxsw_sp_lag_create(struct mlxsw_sp *mlxsw_sp, u16 lag_id)
41980d65fc13SJiri Pirko {
41990d65fc13SJiri Pirko char sldr_pl[MLXSW_REG_SLDR_LEN];
42000d65fc13SJiri Pirko
42010d65fc13SJiri Pirko mlxsw_reg_sldr_lag_create_pack(sldr_pl, lag_id);
42020d65fc13SJiri Pirko return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(sldr), sldr_pl);
42030d65fc13SJiri Pirko }
42040d65fc13SJiri Pirko
mlxsw_sp_lag_destroy(struct mlxsw_sp * mlxsw_sp,u16 lag_id)42050d65fc13SJiri Pirko static int mlxsw_sp_lag_destroy(struct mlxsw_sp *mlxsw_sp, u16 lag_id)
42060d65fc13SJiri Pirko {
42070d65fc13SJiri Pirko char sldr_pl[MLXSW_REG_SLDR_LEN];
42080d65fc13SJiri Pirko
42090d65fc13SJiri Pirko mlxsw_reg_sldr_lag_destroy_pack(sldr_pl, lag_id);
42100d65fc13SJiri Pirko return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(sldr), sldr_pl);
42110d65fc13SJiri Pirko }
42120d65fc13SJiri Pirko
mlxsw_sp_lag_col_port_add(struct mlxsw_sp_port * mlxsw_sp_port,u16 lag_id,u8 port_index)42130d65fc13SJiri Pirko static int mlxsw_sp_lag_col_port_add(struct mlxsw_sp_port *mlxsw_sp_port,
42140d65fc13SJiri Pirko u16 lag_id, u8 port_index)
42150d65fc13SJiri Pirko {
42160d65fc13SJiri Pirko struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
42170d65fc13SJiri Pirko char slcor_pl[MLXSW_REG_SLCOR_LEN];
42180d65fc13SJiri Pirko
42190d65fc13SJiri Pirko mlxsw_reg_slcor_port_add_pack(slcor_pl, mlxsw_sp_port->local_port,
42200d65fc13SJiri Pirko lag_id, port_index);
42210d65fc13SJiri Pirko return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(slcor), slcor_pl);
42220d65fc13SJiri Pirko }
42230d65fc13SJiri Pirko
mlxsw_sp_lag_col_port_remove(struct mlxsw_sp_port * mlxsw_sp_port,u16 lag_id)42240d65fc13SJiri Pirko static int mlxsw_sp_lag_col_port_remove(struct mlxsw_sp_port *mlxsw_sp_port,
42250d65fc13SJiri Pirko u16 lag_id)
42260d65fc13SJiri Pirko {
42270d65fc13SJiri Pirko struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
42280d65fc13SJiri Pirko char slcor_pl[MLXSW_REG_SLCOR_LEN];
42290d65fc13SJiri Pirko
42300d65fc13SJiri Pirko mlxsw_reg_slcor_port_remove_pack(slcor_pl, mlxsw_sp_port->local_port,
42310d65fc13SJiri Pirko lag_id);
42320d65fc13SJiri Pirko return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(slcor), slcor_pl);
42330d65fc13SJiri Pirko }
42340d65fc13SJiri Pirko
mlxsw_sp_lag_col_port_enable(struct mlxsw_sp_port * mlxsw_sp_port,u16 lag_id)42350d65fc13SJiri Pirko static int mlxsw_sp_lag_col_port_enable(struct mlxsw_sp_port *mlxsw_sp_port,
42360d65fc13SJiri Pirko u16 lag_id)
42370d65fc13SJiri Pirko {
42380d65fc13SJiri Pirko struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
42390d65fc13SJiri Pirko char slcor_pl[MLXSW_REG_SLCOR_LEN];
42400d65fc13SJiri Pirko
42410d65fc13SJiri Pirko mlxsw_reg_slcor_col_enable_pack(slcor_pl, mlxsw_sp_port->local_port,
42420d65fc13SJiri Pirko lag_id);
42430d65fc13SJiri Pirko return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(slcor), slcor_pl);
42440d65fc13SJiri Pirko }
42450d65fc13SJiri Pirko
mlxsw_sp_lag_col_port_disable(struct mlxsw_sp_port * mlxsw_sp_port,u16 lag_id)42460d65fc13SJiri Pirko static int mlxsw_sp_lag_col_port_disable(struct mlxsw_sp_port *mlxsw_sp_port,
42470d65fc13SJiri Pirko u16 lag_id)
42480d65fc13SJiri Pirko {
42490d65fc13SJiri Pirko struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
42500d65fc13SJiri Pirko char slcor_pl[MLXSW_REG_SLCOR_LEN];
42510d65fc13SJiri Pirko
42520d65fc13SJiri Pirko mlxsw_reg_slcor_col_disable_pack(slcor_pl, mlxsw_sp_port->local_port,
42530d65fc13SJiri Pirko lag_id);
42540d65fc13SJiri Pirko return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(slcor), slcor_pl);
42550d65fc13SJiri Pirko }
42560d65fc13SJiri Pirko
mlxsw_sp_lag_index_get(struct mlxsw_sp * mlxsw_sp,struct net_device * lag_dev,u16 * p_lag_id)42570d65fc13SJiri Pirko static int mlxsw_sp_lag_index_get(struct mlxsw_sp *mlxsw_sp,
42580d65fc13SJiri Pirko struct net_device *lag_dev,
42590d65fc13SJiri Pirko u16 *p_lag_id)
42600d65fc13SJiri Pirko {
42610d65fc13SJiri Pirko struct mlxsw_sp_upper *lag;
42620d65fc13SJiri Pirko int free_lag_id = -1;
4263cf735d4cSAmit Cohen u16 max_lag;
4264cf735d4cSAmit Cohen int err, i;
42650d65fc13SJiri Pirko
4266cf735d4cSAmit Cohen err = mlxsw_core_max_lag(mlxsw_sp->core, &max_lag);
4267cf735d4cSAmit Cohen if (err)
4268cf735d4cSAmit Cohen return err;
4269cf735d4cSAmit Cohen
4270c1a38311SJiri Pirko for (i = 0; i < max_lag; i++) {
42710d65fc13SJiri Pirko lag = mlxsw_sp_lag_get(mlxsw_sp, i);
42720d65fc13SJiri Pirko if (lag->ref_count) {
42730d65fc13SJiri Pirko if (lag->dev == lag_dev) {
42740d65fc13SJiri Pirko *p_lag_id = i;
42750d65fc13SJiri Pirko return 0;
42760d65fc13SJiri Pirko }
42770d65fc13SJiri Pirko } else if (free_lag_id < 0) {
42780d65fc13SJiri Pirko free_lag_id = i;
42790d65fc13SJiri Pirko }
42800d65fc13SJiri Pirko }
42810d65fc13SJiri Pirko if (free_lag_id < 0)
42820d65fc13SJiri Pirko return -EBUSY;
42830d65fc13SJiri Pirko *p_lag_id = free_lag_id;
42840d65fc13SJiri Pirko return 0;
42850d65fc13SJiri Pirko }
42860d65fc13SJiri Pirko
42870d65fc13SJiri Pirko static bool
mlxsw_sp_master_lag_check(struct mlxsw_sp * mlxsw_sp,struct net_device * lag_dev,struct netdev_lag_upper_info * lag_upper_info,struct netlink_ext_ack * extack)42880d65fc13SJiri Pirko mlxsw_sp_master_lag_check(struct mlxsw_sp *mlxsw_sp,
42890d65fc13SJiri Pirko struct net_device *lag_dev,
4290e58376e1SDavid Ahern struct netdev_lag_upper_info *lag_upper_info,
4291e58376e1SDavid Ahern struct netlink_ext_ack *extack)
42920d65fc13SJiri Pirko {
42930d65fc13SJiri Pirko u16 lag_id;
42940d65fc13SJiri Pirko
4295e58376e1SDavid Ahern if (mlxsw_sp_lag_index_get(mlxsw_sp, lag_dev, &lag_id) != 0) {
42966c677750SArkadi Sharshevsky NL_SET_ERR_MSG_MOD(extack, "Exceeded number of supported LAG devices");
42970d65fc13SJiri Pirko return false;
4298e58376e1SDavid Ahern }
4299e58376e1SDavid Ahern if (lag_upper_info->tx_type != NETDEV_LAG_TX_TYPE_HASH) {
43006c677750SArkadi Sharshevsky NL_SET_ERR_MSG_MOD(extack, "LAG device using unsupported Tx type");
43010d65fc13SJiri Pirko return false;
4302e58376e1SDavid Ahern }
43030d65fc13SJiri Pirko return true;
43040d65fc13SJiri Pirko }
43050d65fc13SJiri Pirko
mlxsw_sp_port_lag_index_get(struct mlxsw_sp * mlxsw_sp,u16 lag_id,u8 * p_port_index)43060d65fc13SJiri Pirko static int mlxsw_sp_port_lag_index_get(struct mlxsw_sp *mlxsw_sp,
43070d65fc13SJiri Pirko u16 lag_id, u8 *p_port_index)
43080d65fc13SJiri Pirko {
4309c1a38311SJiri Pirko u64 max_lag_members;
43100d65fc13SJiri Pirko int i;
43110d65fc13SJiri Pirko
4312c1a38311SJiri Pirko max_lag_members = MLXSW_CORE_RES_GET(mlxsw_sp->core,
4313c1a38311SJiri Pirko MAX_LAG_MEMBERS);
4314c1a38311SJiri Pirko for (i = 0; i < max_lag_members; i++) {
43150d65fc13SJiri Pirko if (!mlxsw_sp_port_lagged_get(mlxsw_sp, lag_id, i)) {
43160d65fc13SJiri Pirko *p_port_index = i;
43170d65fc13SJiri Pirko return 0;
43180d65fc13SJiri Pirko }
43190d65fc13SJiri Pirko }
43200d65fc13SJiri Pirko return -EBUSY;
43210d65fc13SJiri Pirko }
43220d65fc13SJiri Pirko
mlxsw_sp_lag_uppers_bridge_join(struct mlxsw_sp_port * mlxsw_sp_port,struct net_device * lag_dev,struct netlink_ext_ack * extack)4323987c7782SPetr Machata static int mlxsw_sp_lag_uppers_bridge_join(struct mlxsw_sp_port *mlxsw_sp_port,
4324987c7782SPetr Machata struct net_device *lag_dev,
4325987c7782SPetr Machata struct netlink_ext_ack *extack)
4326987c7782SPetr Machata {
4327987c7782SPetr Machata struct net_device *upper_dev;
4328987c7782SPetr Machata struct net_device *master;
4329987c7782SPetr Machata struct list_head *iter;
4330987c7782SPetr Machata int done = 0;
4331987c7782SPetr Machata int err;
4332987c7782SPetr Machata
4333987c7782SPetr Machata master = netdev_master_upper_dev_get(lag_dev);
4334987c7782SPetr Machata if (master && netif_is_bridge_master(master)) {
4335987c7782SPetr Machata err = mlxsw_sp_port_bridge_join(mlxsw_sp_port, lag_dev, master,
4336987c7782SPetr Machata extack);
4337987c7782SPetr Machata if (err)
4338987c7782SPetr Machata return err;
4339987c7782SPetr Machata }
4340987c7782SPetr Machata
4341987c7782SPetr Machata netdev_for_each_upper_dev_rcu(lag_dev, upper_dev, iter) {
4342987c7782SPetr Machata if (!is_vlan_dev(upper_dev))
4343987c7782SPetr Machata continue;
4344987c7782SPetr Machata
4345987c7782SPetr Machata master = netdev_master_upper_dev_get(upper_dev);
4346987c7782SPetr Machata if (master && netif_is_bridge_master(master)) {
4347987c7782SPetr Machata err = mlxsw_sp_port_bridge_join(mlxsw_sp_port,
4348987c7782SPetr Machata upper_dev, master,
4349987c7782SPetr Machata extack);
4350987c7782SPetr Machata if (err)
4351987c7782SPetr Machata goto err_port_bridge_join;
4352987c7782SPetr Machata }
4353987c7782SPetr Machata
4354987c7782SPetr Machata ++done;
4355987c7782SPetr Machata }
4356987c7782SPetr Machata
4357987c7782SPetr Machata return 0;
4358987c7782SPetr Machata
4359987c7782SPetr Machata err_port_bridge_join:
4360987c7782SPetr Machata netdev_for_each_upper_dev_rcu(lag_dev, upper_dev, iter) {
4361987c7782SPetr Machata if (!is_vlan_dev(upper_dev))
4362987c7782SPetr Machata continue;
4363987c7782SPetr Machata
4364987c7782SPetr Machata master = netdev_master_upper_dev_get(upper_dev);
4365987c7782SPetr Machata if (!master || !netif_is_bridge_master(master))
4366987c7782SPetr Machata continue;
4367987c7782SPetr Machata
4368987c7782SPetr Machata if (!done--)
4369987c7782SPetr Machata break;
4370987c7782SPetr Machata
4371987c7782SPetr Machata mlxsw_sp_port_bridge_leave(mlxsw_sp_port, upper_dev, master);
4372987c7782SPetr Machata }
4373987c7782SPetr Machata
4374987c7782SPetr Machata master = netdev_master_upper_dev_get(lag_dev);
4375987c7782SPetr Machata if (master && netif_is_bridge_master(master))
4376987c7782SPetr Machata mlxsw_sp_port_bridge_leave(mlxsw_sp_port, lag_dev, master);
4377987c7782SPetr Machata
4378987c7782SPetr Machata return err;
4379987c7782SPetr Machata }
4380987c7782SPetr Machata
4381987c7782SPetr Machata static void
mlxsw_sp_lag_uppers_bridge_leave(struct mlxsw_sp_port * mlxsw_sp_port,struct net_device * lag_dev)4382987c7782SPetr Machata mlxsw_sp_lag_uppers_bridge_leave(struct mlxsw_sp_port *mlxsw_sp_port,
4383987c7782SPetr Machata struct net_device *lag_dev)
4384987c7782SPetr Machata {
4385987c7782SPetr Machata struct net_device *upper_dev;
4386987c7782SPetr Machata struct net_device *master;
4387987c7782SPetr Machata struct list_head *iter;
4388987c7782SPetr Machata
4389987c7782SPetr Machata netdev_for_each_upper_dev_rcu(lag_dev, upper_dev, iter) {
4390987c7782SPetr Machata if (!is_vlan_dev(upper_dev))
4391987c7782SPetr Machata continue;
4392987c7782SPetr Machata
4393987c7782SPetr Machata master = netdev_master_upper_dev_get(upper_dev);
4394987c7782SPetr Machata if (!master)
4395987c7782SPetr Machata continue;
4396987c7782SPetr Machata
4397987c7782SPetr Machata mlxsw_sp_port_bridge_leave(mlxsw_sp_port, upper_dev, master);
4398987c7782SPetr Machata }
4399987c7782SPetr Machata
4400987c7782SPetr Machata master = netdev_master_upper_dev_get(lag_dev);
4401987c7782SPetr Machata if (master)
4402987c7782SPetr Machata mlxsw_sp_port_bridge_leave(mlxsw_sp_port, lag_dev, master);
4403987c7782SPetr Machata }
4404987c7782SPetr Machata
mlxsw_sp_port_lag_join(struct mlxsw_sp_port * mlxsw_sp_port,struct net_device * lag_dev,struct netlink_ext_ack * extack)44050d65fc13SJiri Pirko static int mlxsw_sp_port_lag_join(struct mlxsw_sp_port *mlxsw_sp_port,
440631e1de4fSIdo Schimmel struct net_device *lag_dev,
440731e1de4fSIdo Schimmel struct netlink_ext_ack *extack)
44080d65fc13SJiri Pirko {
44090d65fc13SJiri Pirko struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
44100d65fc13SJiri Pirko struct mlxsw_sp_upper *lag;
44110d65fc13SJiri Pirko u16 lag_id;
44120d65fc13SJiri Pirko u8 port_index;
44130d65fc13SJiri Pirko int err;
44140d65fc13SJiri Pirko
44150d65fc13SJiri Pirko err = mlxsw_sp_lag_index_get(mlxsw_sp, lag_dev, &lag_id);
44160d65fc13SJiri Pirko if (err)
44170d65fc13SJiri Pirko return err;
44180d65fc13SJiri Pirko lag = mlxsw_sp_lag_get(mlxsw_sp, lag_id);
44190d65fc13SJiri Pirko if (!lag->ref_count) {
44200d65fc13SJiri Pirko err = mlxsw_sp_lag_create(mlxsw_sp, lag_id);
44210d65fc13SJiri Pirko if (err)
44220d65fc13SJiri Pirko return err;
44230d65fc13SJiri Pirko lag->dev = lag_dev;
44240d65fc13SJiri Pirko }
44250d65fc13SJiri Pirko
44260d65fc13SJiri Pirko err = mlxsw_sp_port_lag_index_get(mlxsw_sp, lag_id, &port_index);
44270d65fc13SJiri Pirko if (err)
44280d65fc13SJiri Pirko return err;
4429987c7782SPetr Machata
4430987c7782SPetr Machata err = mlxsw_sp_lag_uppers_bridge_join(mlxsw_sp_port, lag_dev,
4431987c7782SPetr Machata extack);
4432987c7782SPetr Machata if (err)
4433987c7782SPetr Machata goto err_lag_uppers_bridge_join;
4434987c7782SPetr Machata
44350d65fc13SJiri Pirko err = mlxsw_sp_lag_col_port_add(mlxsw_sp_port, lag_id, port_index);
44360d65fc13SJiri Pirko if (err)
44370d65fc13SJiri Pirko goto err_col_port_add;
44380d65fc13SJiri Pirko
44390d65fc13SJiri Pirko mlxsw_core_lag_mapping_set(mlxsw_sp->core, lag_id, port_index,
44400d65fc13SJiri Pirko mlxsw_sp_port->local_port);
44410d65fc13SJiri Pirko mlxsw_sp_port->lag_id = lag_id;
44420d65fc13SJiri Pirko mlxsw_sp_port->lagged = 1;
44430d65fc13SJiri Pirko lag->ref_count++;
444486bf95b3SIdo Schimmel
4445c57529e1SIdo Schimmel /* Port is no longer usable as a router interface */
44460417d25eSIdo Schimmel if (mlxsw_sp_port->default_vlan->fid)
44470417d25eSIdo Schimmel mlxsw_sp_port_vlan_router_leave(mlxsw_sp_port->default_vlan);
444886bf95b3SIdo Schimmel
444931e1de4fSIdo Schimmel /* Join a router interface configured on the LAG, if exists */
445076962b80SPetr Machata err = mlxsw_sp_router_port_join_lag(mlxsw_sp_port, lag_dev,
445176962b80SPetr Machata extack);
445231e1de4fSIdo Schimmel if (err)
445331e1de4fSIdo Schimmel goto err_router_join;
445431e1de4fSIdo Schimmel
445531618b22SPetr Machata err = mlxsw_sp_netdevice_enslavement_replay(mlxsw_sp, lag_dev, extack);
445631618b22SPetr Machata if (err)
445731618b22SPetr Machata goto err_replay;
445831618b22SPetr Machata
44590d65fc13SJiri Pirko return 0;
44600d65fc13SJiri Pirko
446131618b22SPetr Machata err_replay:
446231618b22SPetr Machata mlxsw_sp_router_port_leave_lag(mlxsw_sp_port, lag_dev);
446331e1de4fSIdo Schimmel err_router_join:
446431e1de4fSIdo Schimmel lag->ref_count--;
446531e1de4fSIdo Schimmel mlxsw_sp_port->lagged = 0;
446631e1de4fSIdo Schimmel mlxsw_core_lag_mapping_clear(mlxsw_sp->core, lag_id,
446731e1de4fSIdo Schimmel mlxsw_sp_port->local_port);
446831e1de4fSIdo Schimmel mlxsw_sp_lag_col_port_remove(mlxsw_sp_port, lag_id);
44690d65fc13SJiri Pirko err_col_port_add:
4470987c7782SPetr Machata mlxsw_sp_lag_uppers_bridge_leave(mlxsw_sp_port, lag_dev);
4471987c7782SPetr Machata err_lag_uppers_bridge_join:
44720d65fc13SJiri Pirko if (!lag->ref_count)
44730d65fc13SJiri Pirko mlxsw_sp_lag_destroy(mlxsw_sp, lag_id);
44740d65fc13SJiri Pirko return err;
44750d65fc13SJiri Pirko }
44760d65fc13SJiri Pirko
mlxsw_sp_port_lag_leave(struct mlxsw_sp_port * mlxsw_sp_port,struct net_device * lag_dev)447782e6db03SIdo Schimmel static void mlxsw_sp_port_lag_leave(struct mlxsw_sp_port *mlxsw_sp_port,
44780d65fc13SJiri Pirko struct net_device *lag_dev)
44790d65fc13SJiri Pirko {
44800d65fc13SJiri Pirko struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
44810d65fc13SJiri Pirko u16 lag_id = mlxsw_sp_port->lag_id;
44821c800759SIdo Schimmel struct mlxsw_sp_upper *lag;
44830d65fc13SJiri Pirko
44840d65fc13SJiri Pirko if (!mlxsw_sp_port->lagged)
448582e6db03SIdo Schimmel return;
44860d65fc13SJiri Pirko lag = mlxsw_sp_lag_get(mlxsw_sp, lag_id);
44870d65fc13SJiri Pirko WARN_ON(lag->ref_count == 0);
44880d65fc13SJiri Pirko
448982e6db03SIdo Schimmel mlxsw_sp_lag_col_port_remove(mlxsw_sp_port, lag_id);
44900d65fc13SJiri Pirko
4491c57529e1SIdo Schimmel /* Any VLANs configured on the port are no longer valid */
44920417d25eSIdo Schimmel mlxsw_sp_port_vlan_flush(mlxsw_sp_port, false);
44930417d25eSIdo Schimmel mlxsw_sp_port_vlan_cleanup(mlxsw_sp_port->default_vlan);
4494be2d6f42SIdo Schimmel /* Make the LAG and its directly linked uppers leave bridges they
4495be2d6f42SIdo Schimmel * are memeber in
4496be2d6f42SIdo Schimmel */
4497be2d6f42SIdo Schimmel mlxsw_sp_port_lag_uppers_cleanup(mlxsw_sp_port, lag_dev);
44984dc236c3SIdo Schimmel
4499fe3f6d14SIdo Schimmel if (lag->ref_count == 1)
450082e6db03SIdo Schimmel mlxsw_sp_lag_destroy(mlxsw_sp, lag_id);
45010d65fc13SJiri Pirko
45020d65fc13SJiri Pirko mlxsw_core_lag_mapping_clear(mlxsw_sp->core, lag_id,
45030d65fc13SJiri Pirko mlxsw_sp_port->local_port);
45040d65fc13SJiri Pirko mlxsw_sp_port->lagged = 0;
45050d65fc13SJiri Pirko lag->ref_count--;
450686bf95b3SIdo Schimmel
4507c57529e1SIdo Schimmel /* Make sure untagged frames are allowed to ingress */
45083ae7a65bSAmit Cohen mlxsw_sp_port_pvid_set(mlxsw_sp_port, MLXSW_SP_DEFAULT_VID,
45093ae7a65bSAmit Cohen ETH_P_8021Q);
45100d65fc13SJiri Pirko }
45110d65fc13SJiri Pirko
mlxsw_sp_lag_dist_port_add(struct mlxsw_sp_port * mlxsw_sp_port,u16 lag_id)451274581206SJiri Pirko static int mlxsw_sp_lag_dist_port_add(struct mlxsw_sp_port *mlxsw_sp_port,
451374581206SJiri Pirko u16 lag_id)
451474581206SJiri Pirko {
451574581206SJiri Pirko struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
451674581206SJiri Pirko char sldr_pl[MLXSW_REG_SLDR_LEN];
451774581206SJiri Pirko
451874581206SJiri Pirko mlxsw_reg_sldr_lag_add_port_pack(sldr_pl, lag_id,
451974581206SJiri Pirko mlxsw_sp_port->local_port);
452074581206SJiri Pirko return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(sldr), sldr_pl);
452174581206SJiri Pirko }
452274581206SJiri Pirko
mlxsw_sp_lag_dist_port_remove(struct mlxsw_sp_port * mlxsw_sp_port,u16 lag_id)452374581206SJiri Pirko static int mlxsw_sp_lag_dist_port_remove(struct mlxsw_sp_port *mlxsw_sp_port,
452474581206SJiri Pirko u16 lag_id)
452574581206SJiri Pirko {
452674581206SJiri Pirko struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
452774581206SJiri Pirko char sldr_pl[MLXSW_REG_SLDR_LEN];
452874581206SJiri Pirko
452974581206SJiri Pirko mlxsw_reg_sldr_lag_remove_port_pack(sldr_pl, lag_id,
453074581206SJiri Pirko mlxsw_sp_port->local_port);
453174581206SJiri Pirko return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(sldr), sldr_pl);
453274581206SJiri Pirko }
453374581206SJiri Pirko
453448ebab31SNir Dotan static int
mlxsw_sp_port_lag_col_dist_enable(struct mlxsw_sp_port * mlxsw_sp_port)453548ebab31SNir Dotan mlxsw_sp_port_lag_col_dist_enable(struct mlxsw_sp_port *mlxsw_sp_port)
453674581206SJiri Pirko {
453748ebab31SNir Dotan int err;
453848ebab31SNir Dotan
453948ebab31SNir Dotan err = mlxsw_sp_lag_col_port_enable(mlxsw_sp_port,
454074581206SJiri Pirko mlxsw_sp_port->lag_id);
454148ebab31SNir Dotan if (err)
454248ebab31SNir Dotan return err;
454348ebab31SNir Dotan
454448ebab31SNir Dotan err = mlxsw_sp_lag_dist_port_add(mlxsw_sp_port, mlxsw_sp_port->lag_id);
454548ebab31SNir Dotan if (err)
454648ebab31SNir Dotan goto err_dist_port_add;
454748ebab31SNir Dotan
454848ebab31SNir Dotan return 0;
454948ebab31SNir Dotan
455048ebab31SNir Dotan err_dist_port_add:
455148ebab31SNir Dotan mlxsw_sp_lag_col_port_disable(mlxsw_sp_port, mlxsw_sp_port->lag_id);
455248ebab31SNir Dotan return err;
455348ebab31SNir Dotan }
455448ebab31SNir Dotan
455548ebab31SNir Dotan static int
mlxsw_sp_port_lag_col_dist_disable(struct mlxsw_sp_port * mlxsw_sp_port)455648ebab31SNir Dotan mlxsw_sp_port_lag_col_dist_disable(struct mlxsw_sp_port *mlxsw_sp_port)
455748ebab31SNir Dotan {
455848ebab31SNir Dotan int err;
455948ebab31SNir Dotan
456048ebab31SNir Dotan err = mlxsw_sp_lag_dist_port_remove(mlxsw_sp_port,
456174581206SJiri Pirko mlxsw_sp_port->lag_id);
456248ebab31SNir Dotan if (err)
456348ebab31SNir Dotan return err;
456448ebab31SNir Dotan
456548ebab31SNir Dotan err = mlxsw_sp_lag_col_port_disable(mlxsw_sp_port,
456648ebab31SNir Dotan mlxsw_sp_port->lag_id);
456748ebab31SNir Dotan if (err)
456848ebab31SNir Dotan goto err_col_port_disable;
456948ebab31SNir Dotan
457048ebab31SNir Dotan return 0;
457148ebab31SNir Dotan
457248ebab31SNir Dotan err_col_port_disable:
457348ebab31SNir Dotan mlxsw_sp_lag_dist_port_add(mlxsw_sp_port, mlxsw_sp_port->lag_id);
457448ebab31SNir Dotan return err;
457574581206SJiri Pirko }
457674581206SJiri Pirko
mlxsw_sp_port_lag_changed(struct mlxsw_sp_port * mlxsw_sp_port,struct netdev_lag_lower_state_info * info)457774581206SJiri Pirko static int mlxsw_sp_port_lag_changed(struct mlxsw_sp_port *mlxsw_sp_port,
457874581206SJiri Pirko struct netdev_lag_lower_state_info *info)
457974581206SJiri Pirko {
458048ebab31SNir Dotan if (info->tx_enabled)
458148ebab31SNir Dotan return mlxsw_sp_port_lag_col_dist_enable(mlxsw_sp_port);
458248ebab31SNir Dotan else
458348ebab31SNir Dotan return mlxsw_sp_port_lag_col_dist_disable(mlxsw_sp_port);
458474581206SJiri Pirko }
458574581206SJiri Pirko
mlxsw_sp_port_stp_set(struct mlxsw_sp_port * mlxsw_sp_port,bool enable)45862b94e58dSJiri Pirko static int mlxsw_sp_port_stp_set(struct mlxsw_sp_port *mlxsw_sp_port,
45872b94e58dSJiri Pirko bool enable)
45882b94e58dSJiri Pirko {
45892b94e58dSJiri Pirko struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
45902b94e58dSJiri Pirko enum mlxsw_reg_spms_state spms_state;
45912b94e58dSJiri Pirko char *spms_pl;
45922b94e58dSJiri Pirko u16 vid;
45932b94e58dSJiri Pirko int err;
45942b94e58dSJiri Pirko
45952b94e58dSJiri Pirko spms_state = enable ? MLXSW_REG_SPMS_STATE_FORWARDING :
45962b94e58dSJiri Pirko MLXSW_REG_SPMS_STATE_DISCARDING;
45972b94e58dSJiri Pirko
45982b94e58dSJiri Pirko spms_pl = kmalloc(MLXSW_REG_SPMS_LEN, GFP_KERNEL);
45992b94e58dSJiri Pirko if (!spms_pl)
46002b94e58dSJiri Pirko return -ENOMEM;
46012b94e58dSJiri Pirko mlxsw_reg_spms_pack(spms_pl, mlxsw_sp_port->local_port);
46022b94e58dSJiri Pirko
46032b94e58dSJiri Pirko for (vid = 0; vid < VLAN_N_VID; vid++)
46042b94e58dSJiri Pirko mlxsw_reg_spms_vid_pack(spms_pl, vid, spms_state);
46052b94e58dSJiri Pirko
46062b94e58dSJiri Pirko err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(spms), spms_pl);
46072b94e58dSJiri Pirko kfree(spms_pl);
46082b94e58dSJiri Pirko return err;
46092b94e58dSJiri Pirko }
46102b94e58dSJiri Pirko
mlxsw_sp_port_ovs_join(struct mlxsw_sp_port * mlxsw_sp_port)46112b94e58dSJiri Pirko static int mlxsw_sp_port_ovs_join(struct mlxsw_sp_port *mlxsw_sp_port)
46122b94e58dSJiri Pirko {
4613fccff086SYuval Mintz u16 vid = 1;
46142b94e58dSJiri Pirko int err;
46152b94e58dSJiri Pirko
46164aafc368SIdo Schimmel err = mlxsw_sp_port_vp_mode_set(mlxsw_sp_port, true);
46172b94e58dSJiri Pirko if (err)
46182b94e58dSJiri Pirko return err;
46194aafc368SIdo Schimmel err = mlxsw_sp_port_stp_set(mlxsw_sp_port, true);
46204aafc368SIdo Schimmel if (err)
46214aafc368SIdo Schimmel goto err_port_stp_set;
46220417d25eSIdo Schimmel err = mlxsw_sp_port_vlan_set(mlxsw_sp_port, 1, VLAN_N_VID - 2,
46232b94e58dSJiri Pirko true, false);
46242b94e58dSJiri Pirko if (err)
46252b94e58dSJiri Pirko goto err_port_vlan_set;
4626fccff086SYuval Mintz
4627fccff086SYuval Mintz for (; vid <= VLAN_N_VID - 1; vid++) {
4628fccff086SYuval Mintz err = mlxsw_sp_port_vid_learning_set(mlxsw_sp_port,
4629fccff086SYuval Mintz vid, false);
4630fccff086SYuval Mintz if (err)
4631fccff086SYuval Mintz goto err_vid_learning_set;
4632fccff086SYuval Mintz }
4633fccff086SYuval Mintz
46342b94e58dSJiri Pirko return 0;
46352b94e58dSJiri Pirko
4636fccff086SYuval Mintz err_vid_learning_set:
4637fccff086SYuval Mintz for (vid--; vid >= 1; vid--)
4638fccff086SYuval Mintz mlxsw_sp_port_vid_learning_set(mlxsw_sp_port, vid, true);
46392b94e58dSJiri Pirko err_port_vlan_set:
46402b94e58dSJiri Pirko mlxsw_sp_port_stp_set(mlxsw_sp_port, false);
46414aafc368SIdo Schimmel err_port_stp_set:
46424aafc368SIdo Schimmel mlxsw_sp_port_vp_mode_set(mlxsw_sp_port, false);
46432b94e58dSJiri Pirko return err;
46442b94e58dSJiri Pirko }
46452b94e58dSJiri Pirko
mlxsw_sp_port_ovs_leave(struct mlxsw_sp_port * mlxsw_sp_port)46462b94e58dSJiri Pirko static void mlxsw_sp_port_ovs_leave(struct mlxsw_sp_port *mlxsw_sp_port)
46472b94e58dSJiri Pirko {
4648fccff086SYuval Mintz u16 vid;
4649fccff086SYuval Mintz
4650fccff086SYuval Mintz for (vid = VLAN_N_VID - 1; vid >= 1; vid--)
4651fccff086SYuval Mintz mlxsw_sp_port_vid_learning_set(mlxsw_sp_port,
4652fccff086SYuval Mintz vid, true);
4653fccff086SYuval Mintz
46540417d25eSIdo Schimmel mlxsw_sp_port_vlan_set(mlxsw_sp_port, 1, VLAN_N_VID - 2,
46552b94e58dSJiri Pirko false, false);
46562b94e58dSJiri Pirko mlxsw_sp_port_stp_set(mlxsw_sp_port, false);
46574aafc368SIdo Schimmel mlxsw_sp_port_vp_mode_set(mlxsw_sp_port, false);
46582b94e58dSJiri Pirko }
46592b94e58dSJiri Pirko
mlxsw_sp_bridge_has_multiple_vxlans(struct net_device * br_dev)46601c30d183SIdo Schimmel static bool mlxsw_sp_bridge_has_multiple_vxlans(struct net_device *br_dev)
46611c30d183SIdo Schimmel {
46621c30d183SIdo Schimmel unsigned int num_vxlans = 0;
46631c30d183SIdo Schimmel struct net_device *dev;
46641c30d183SIdo Schimmel struct list_head *iter;
46651c30d183SIdo Schimmel
46661c30d183SIdo Schimmel netdev_for_each_lower_dev(br_dev, dev, iter) {
46671c30d183SIdo Schimmel if (netif_is_vxlan(dev))
46681c30d183SIdo Schimmel num_vxlans++;
46691c30d183SIdo Schimmel }
46701c30d183SIdo Schimmel
46711c30d183SIdo Schimmel return num_vxlans > 1;
46721c30d183SIdo Schimmel }
46731c30d183SIdo Schimmel
mlxsw_sp_bridge_vxlan_vlan_is_valid(struct net_device * br_dev)4674d70e42b2SIdo Schimmel static bool mlxsw_sp_bridge_vxlan_vlan_is_valid(struct net_device *br_dev)
4675d70e42b2SIdo Schimmel {
4676d70e42b2SIdo Schimmel DECLARE_BITMAP(vlans, VLAN_N_VID) = {0};
4677d70e42b2SIdo Schimmel struct net_device *dev;
4678d70e42b2SIdo Schimmel struct list_head *iter;
4679d70e42b2SIdo Schimmel
4680d70e42b2SIdo Schimmel netdev_for_each_lower_dev(br_dev, dev, iter) {
4681d70e42b2SIdo Schimmel u16 pvid;
4682d70e42b2SIdo Schimmel int err;
4683d70e42b2SIdo Schimmel
4684d70e42b2SIdo Schimmel if (!netif_is_vxlan(dev))
4685d70e42b2SIdo Schimmel continue;
4686d70e42b2SIdo Schimmel
4687d70e42b2SIdo Schimmel err = mlxsw_sp_vxlan_mapped_vid(dev, &pvid);
4688d70e42b2SIdo Schimmel if (err || !pvid)
4689d70e42b2SIdo Schimmel continue;
4690d70e42b2SIdo Schimmel
4691d70e42b2SIdo Schimmel if (test_and_set_bit(pvid, vlans))
4692d70e42b2SIdo Schimmel return false;
4693d70e42b2SIdo Schimmel }
4694d70e42b2SIdo Schimmel
4695d70e42b2SIdo Schimmel return true;
4696d70e42b2SIdo Schimmel }
4697d70e42b2SIdo Schimmel
mlxsw_sp_bridge_vxlan_is_valid(struct net_device * br_dev,struct netlink_ext_ack * extack)46981c30d183SIdo Schimmel static bool mlxsw_sp_bridge_vxlan_is_valid(struct net_device *br_dev,
46991c30d183SIdo Schimmel struct netlink_ext_ack *extack)
47001c30d183SIdo Schimmel {
47011c30d183SIdo Schimmel if (br_multicast_enabled(br_dev)) {
47021c30d183SIdo Schimmel NL_SET_ERR_MSG_MOD(extack, "Multicast can not be enabled on a bridge with a VxLAN device");
47031c30d183SIdo Schimmel return false;
47041c30d183SIdo Schimmel }
47051c30d183SIdo Schimmel
4706d70e42b2SIdo Schimmel if (!br_vlan_enabled(br_dev) &&
4707d70e42b2SIdo Schimmel mlxsw_sp_bridge_has_multiple_vxlans(br_dev)) {
4708d70e42b2SIdo Schimmel NL_SET_ERR_MSG_MOD(extack, "Multiple VxLAN devices are not supported in a VLAN-unaware bridge");
47091c30d183SIdo Schimmel return false;
47101c30d183SIdo Schimmel }
47111c30d183SIdo Schimmel
4712d70e42b2SIdo Schimmel if (br_vlan_enabled(br_dev) &&
4713d70e42b2SIdo Schimmel !mlxsw_sp_bridge_vxlan_vlan_is_valid(br_dev)) {
4714d70e42b2SIdo Schimmel NL_SET_ERR_MSG_MOD(extack, "Multiple VxLAN devices cannot have the same VLAN as PVID and egress untagged");
47151c30d183SIdo Schimmel return false;
47161c30d183SIdo Schimmel }
47171c30d183SIdo Schimmel
47181c30d183SIdo Schimmel return true;
47191c30d183SIdo Schimmel }
47201c30d183SIdo Schimmel
mlxsw_sp_netdev_is_master(struct net_device * upper_dev,struct net_device * dev)4721*2c5ffe8dSPetr Machata static bool mlxsw_sp_netdev_is_master(struct net_device *upper_dev,
4722*2c5ffe8dSPetr Machata struct net_device *dev)
4723*2c5ffe8dSPetr Machata {
4724*2c5ffe8dSPetr Machata return upper_dev == netdev_master_upper_dev_get(dev);
4725*2c5ffe8dSPetr Machata }
4726*2c5ffe8dSPetr Machata
4727*2c5ffe8dSPetr Machata static int __mlxsw_sp_netdevice_event(struct mlxsw_sp *mlxsw_sp,
4728*2c5ffe8dSPetr Machata unsigned long event, void *ptr,
4729*2c5ffe8dSPetr Machata bool process_foreign);
4730*2c5ffe8dSPetr Machata
mlxsw_sp_netdevice_validate_uppers(struct mlxsw_sp * mlxsw_sp,struct net_device * dev,struct netlink_ext_ack * extack)4731*2c5ffe8dSPetr Machata static int mlxsw_sp_netdevice_validate_uppers(struct mlxsw_sp *mlxsw_sp,
4732*2c5ffe8dSPetr Machata struct net_device *dev,
4733*2c5ffe8dSPetr Machata struct netlink_ext_ack *extack)
4734*2c5ffe8dSPetr Machata {
4735*2c5ffe8dSPetr Machata struct net_device *upper_dev;
4736*2c5ffe8dSPetr Machata struct list_head *iter;
4737*2c5ffe8dSPetr Machata int err;
4738*2c5ffe8dSPetr Machata
4739*2c5ffe8dSPetr Machata netdev_for_each_upper_dev_rcu(dev, upper_dev, iter) {
4740*2c5ffe8dSPetr Machata struct netdev_notifier_changeupper_info info = {
4741*2c5ffe8dSPetr Machata .info = {
4742*2c5ffe8dSPetr Machata .dev = dev,
4743*2c5ffe8dSPetr Machata .extack = extack,
4744*2c5ffe8dSPetr Machata },
4745*2c5ffe8dSPetr Machata .master = mlxsw_sp_netdev_is_master(upper_dev, dev),
4746*2c5ffe8dSPetr Machata .upper_dev = upper_dev,
4747*2c5ffe8dSPetr Machata .linking = true,
4748*2c5ffe8dSPetr Machata
4749*2c5ffe8dSPetr Machata /* upper_info is relevant for LAG devices. But we would
4750*2c5ffe8dSPetr Machata * only need this if LAG were a valid upper above
4751*2c5ffe8dSPetr Machata * another upper (e.g. a bridge that is a member of a
4752*2c5ffe8dSPetr Machata * LAG), and that is never a valid configuration. So we
4753*2c5ffe8dSPetr Machata * can keep this as NULL.
4754*2c5ffe8dSPetr Machata */
4755*2c5ffe8dSPetr Machata .upper_info = NULL,
4756*2c5ffe8dSPetr Machata };
4757*2c5ffe8dSPetr Machata
4758*2c5ffe8dSPetr Machata err = __mlxsw_sp_netdevice_event(mlxsw_sp,
4759*2c5ffe8dSPetr Machata NETDEV_PRECHANGEUPPER,
4760*2c5ffe8dSPetr Machata &info, true);
4761*2c5ffe8dSPetr Machata if (err)
4762*2c5ffe8dSPetr Machata return err;
4763*2c5ffe8dSPetr Machata
4764*2c5ffe8dSPetr Machata err = mlxsw_sp_netdevice_validate_uppers(mlxsw_sp, upper_dev,
4765*2c5ffe8dSPetr Machata extack);
4766*2c5ffe8dSPetr Machata if (err)
4767*2c5ffe8dSPetr Machata return err;
4768*2c5ffe8dSPetr Machata }
4769*2c5ffe8dSPetr Machata
4770*2c5ffe8dSPetr Machata return 0;
4771*2c5ffe8dSPetr Machata }
4772*2c5ffe8dSPetr Machata
mlxsw_sp_netdevice_port_upper_event(struct net_device * lower_dev,struct net_device * dev,unsigned long event,void * ptr,bool replay_deslavement)4773f0cebd81SIdo Schimmel static int mlxsw_sp_netdevice_port_upper_event(struct net_device *lower_dev,
4774f0cebd81SIdo Schimmel struct net_device *dev,
47751c47e65bSPetr Machata unsigned long event, void *ptr,
47761c47e65bSPetr Machata bool replay_deslavement)
477756ade8feSJiri Pirko {
477856ade8feSJiri Pirko struct netdev_notifier_changeupper_info *info;
477956ade8feSJiri Pirko struct mlxsw_sp_port *mlxsw_sp_port;
4780e58376e1SDavid Ahern struct netlink_ext_ack *extack;
478156ade8feSJiri Pirko struct net_device *upper_dev;
478256ade8feSJiri Pirko struct mlxsw_sp *mlxsw_sp;
478380bedf1aSIdo Schimmel int err = 0;
478409139f67SDanielle Ratson u16 proto;
478556ade8feSJiri Pirko
478656ade8feSJiri Pirko mlxsw_sp_port = netdev_priv(dev);
478756ade8feSJiri Pirko mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
478856ade8feSJiri Pirko info = ptr;
4789e58376e1SDavid Ahern extack = netdev_notifier_info_to_extack(&info->info);
479056ade8feSJiri Pirko
479156ade8feSJiri Pirko switch (event) {
479256ade8feSJiri Pirko case NETDEV_PRECHANGEUPPER:
479356ade8feSJiri Pirko upper_dev = info->upper_dev;
479459fe9b3fSIdo Schimmel if (!is_vlan_dev(upper_dev) &&
479559fe9b3fSIdo Schimmel !netif_is_lag_master(upper_dev) &&
47967179eb5aSIdo Schimmel !netif_is_bridge_master(upper_dev) &&
4797c5516185SIdo Schimmel !netif_is_ovs_master(upper_dev) &&
47987cf0f96dSPetr Machata !netif_is_macvlan(upper_dev) &&
47997cf0f96dSPetr Machata !netif_is_l3_master(upper_dev)) {
48006c677750SArkadi Sharshevsky NL_SET_ERR_MSG_MOD(extack, "Unknown upper device type");
480159fe9b3fSIdo Schimmel return -EINVAL;
4802e58376e1SDavid Ahern }
48036ec43904SIdo Schimmel if (!info->linking)
48040d65fc13SJiri Pirko break;
48051c30d183SIdo Schimmel if (netif_is_bridge_master(upper_dev) &&
48061c30d183SIdo Schimmel !mlxsw_sp_bridge_device_is_offloaded(mlxsw_sp, upper_dev) &&
48071c30d183SIdo Schimmel mlxsw_sp_bridge_has_vxlan(upper_dev) &&
48081c30d183SIdo Schimmel !mlxsw_sp_bridge_vxlan_is_valid(upper_dev, extack))
48091c30d183SIdo Schimmel return -EOPNOTSUPP;
481090045fc9SIdo Schimmel if (netdev_has_any_upper_dev(upper_dev) &&
481190045fc9SIdo Schimmel (!netif_is_bridge_master(upper_dev) ||
481290045fc9SIdo Schimmel !mlxsw_sp_bridge_device_is_offloaded(mlxsw_sp,
481390045fc9SIdo Schimmel upper_dev))) {
4814*2c5ffe8dSPetr Machata err = mlxsw_sp_netdevice_validate_uppers(mlxsw_sp,
4815*2c5ffe8dSPetr Machata upper_dev,
4816*2c5ffe8dSPetr Machata extack);
4817*2c5ffe8dSPetr Machata if (err)
4818*2c5ffe8dSPetr Machata return err;
4819e58376e1SDavid Ahern }
48200d65fc13SJiri Pirko if (netif_is_lag_master(upper_dev) &&
48210d65fc13SJiri Pirko !mlxsw_sp_master_lag_check(mlxsw_sp, upper_dev,
4822e58376e1SDavid Ahern info->upper_info, extack))
482380bedf1aSIdo Schimmel return -EINVAL;
4824e58376e1SDavid Ahern if (netif_is_lag_master(upper_dev) && vlan_uses_dev(dev)) {
48256c677750SArkadi Sharshevsky NL_SET_ERR_MSG_MOD(extack, "Master device is a LAG master and this device has a VLAN");
48266ec43904SIdo Schimmel return -EINVAL;
4827e58376e1SDavid Ahern }
48286ec43904SIdo Schimmel if (netif_is_lag_port(dev) && is_vlan_dev(upper_dev) &&
4829e58376e1SDavid Ahern !netif_is_lag_master(vlan_dev_real_dev(upper_dev))) {
48306c677750SArkadi Sharshevsky NL_SET_ERR_MSG_MOD(extack, "Can not put a VLAN on a LAG port");
48316ec43904SIdo Schimmel return -EINVAL;
4832e58376e1SDavid Ahern }
4833e58376e1SDavid Ahern if (netif_is_ovs_master(upper_dev) && vlan_uses_dev(dev)) {
48346c677750SArkadi Sharshevsky NL_SET_ERR_MSG_MOD(extack, "Master device is an OVS master and this device has a VLAN");
48352b94e58dSJiri Pirko return -EINVAL;
4836e58376e1SDavid Ahern }
4837e58376e1SDavid Ahern if (netif_is_ovs_port(dev) && is_vlan_dev(upper_dev)) {
48386c677750SArkadi Sharshevsky NL_SET_ERR_MSG_MOD(extack, "Can not put a VLAN on an OVS port");
48392b94e58dSJiri Pirko return -EINVAL;
4840e58376e1SDavid Ahern }
484109139f67SDanielle Ratson if (netif_is_bridge_master(upper_dev)) {
484209139f67SDanielle Ratson br_vlan_get_proto(upper_dev, &proto);
484309139f67SDanielle Ratson if (br_vlan_enabled(upper_dev) &&
484409139f67SDanielle Ratson proto != ETH_P_8021Q && proto != ETH_P_8021AD) {
484509139f67SDanielle Ratson NL_SET_ERR_MSG_MOD(extack, "Enslaving a port to a bridge with unknown VLAN protocol is not supported");
484609139f67SDanielle Ratson return -EOPNOTSUPP;
484709139f67SDanielle Ratson }
484809139f67SDanielle Ratson if (vlan_uses_dev(lower_dev) &&
484909139f67SDanielle Ratson br_vlan_enabled(upper_dev) &&
485009139f67SDanielle Ratson proto == ETH_P_8021AD) {
485109139f67SDanielle Ratson NL_SET_ERR_MSG_MOD(extack, "Enslaving a port that already has a VLAN upper to an 802.1ad bridge is not supported");
485209139f67SDanielle Ratson return -EOPNOTSUPP;
485309139f67SDanielle Ratson }
485409139f67SDanielle Ratson }
485509139f67SDanielle Ratson if (netif_is_bridge_port(lower_dev) && is_vlan_dev(upper_dev)) {
485609139f67SDanielle Ratson struct net_device *br_dev = netdev_master_upper_dev_get(lower_dev);
485709139f67SDanielle Ratson
485809139f67SDanielle Ratson if (br_vlan_enabled(br_dev)) {
485909139f67SDanielle Ratson br_vlan_get_proto(br_dev, &proto);
486009139f67SDanielle Ratson if (proto == ETH_P_8021AD) {
486109139f67SDanielle Ratson NL_SET_ERR_MSG_MOD(extack, "VLAN uppers are not supported on a port enslaved to an 802.1ad bridge");
486209139f67SDanielle Ratson return -EOPNOTSUPP;
486309139f67SDanielle Ratson }
486409139f67SDanielle Ratson }
486509139f67SDanielle Ratson }
486609139f67SDanielle Ratson if (is_vlan_dev(upper_dev) &&
486709139f67SDanielle Ratson ntohs(vlan_dev_vlan_proto(upper_dev)) != ETH_P_8021Q) {
486809139f67SDanielle Ratson NL_SET_ERR_MSG_MOD(extack, "VLAN uppers are only supported with 802.1q VLAN protocol");
486909139f67SDanielle Ratson return -EOPNOTSUPP;
487009139f67SDanielle Ratson }
487125ed8088SIdo Schimmel if (is_vlan_dev(upper_dev) && mlxsw_sp_port->security) {
487225ed8088SIdo Schimmel NL_SET_ERR_MSG_MOD(extack, "VLAN uppers are not supported on a locked port");
487325ed8088SIdo Schimmel return -EOPNOTSUPP;
487425ed8088SIdo Schimmel }
487556ade8feSJiri Pirko break;
487656ade8feSJiri Pirko case NETDEV_CHANGEUPPER:
487756ade8feSJiri Pirko upper_dev = info->upper_dev;
4878c57529e1SIdo Schimmel if (netif_is_bridge_master(upper_dev)) {
48794560cf40SPetr Machata if (info->linking) {
48807117a570SIdo Schimmel err = mlxsw_sp_port_bridge_join(mlxsw_sp_port,
4881f0cebd81SIdo Schimmel lower_dev,
48829b63ef88SIdo Schimmel upper_dev,
48839b63ef88SIdo Schimmel extack);
48844560cf40SPetr Machata } else {
4885f0cebd81SIdo Schimmel mlxsw_sp_port_bridge_leave(mlxsw_sp_port,
4886f0cebd81SIdo Schimmel lower_dev,
4887f0cebd81SIdo Schimmel upper_dev);
48884560cf40SPetr Machata if (!replay_deslavement)
48894560cf40SPetr Machata break;
48904560cf40SPetr Machata mlxsw_sp_netdevice_deslavement_replay(mlxsw_sp,
48914560cf40SPetr Machata lower_dev);
48924560cf40SPetr Machata }
48930d65fc13SJiri Pirko } else if (netif_is_lag_master(upper_dev)) {
48948adbe212SJiri Pirko if (info->linking) {
48950d65fc13SJiri Pirko err = mlxsw_sp_port_lag_join(mlxsw_sp_port,
489631e1de4fSIdo Schimmel upper_dev, extack);
48978adbe212SJiri Pirko } else {
489848ebab31SNir Dotan mlxsw_sp_port_lag_col_dist_disable(mlxsw_sp_port);
489982e6db03SIdo Schimmel mlxsw_sp_port_lag_leave(mlxsw_sp_port,
49000d65fc13SJiri Pirko upper_dev);
49014560cf40SPetr Machata mlxsw_sp_netdevice_deslavement_replay(mlxsw_sp,
49024560cf40SPetr Machata dev);
49038adbe212SJiri Pirko }
49042b94e58dSJiri Pirko } else if (netif_is_ovs_master(upper_dev)) {
49052b94e58dSJiri Pirko if (info->linking)
49062b94e58dSJiri Pirko err = mlxsw_sp_port_ovs_join(mlxsw_sp_port);
49072b94e58dSJiri Pirko else
49082b94e58dSJiri Pirko mlxsw_sp_port_ovs_leave(mlxsw_sp_port);
49092db99378SIdo Schimmel } else if (netif_is_macvlan(upper_dev)) {
49102db99378SIdo Schimmel if (!info->linking)
49112db99378SIdo Schimmel mlxsw_sp_rif_macvlan_del(mlxsw_sp, upper_dev);
4912e149113aSIdo Schimmel } else if (is_vlan_dev(upper_dev)) {
4913e149113aSIdo Schimmel struct net_device *br_dev;
4914e149113aSIdo Schimmel
4915e149113aSIdo Schimmel if (!netif_is_bridge_port(upper_dev))
4916e149113aSIdo Schimmel break;
4917e149113aSIdo Schimmel if (info->linking)
4918e149113aSIdo Schimmel break;
4919e149113aSIdo Schimmel br_dev = netdev_master_upper_dev_get(upper_dev);
4920e149113aSIdo Schimmel mlxsw_sp_port_bridge_leave(mlxsw_sp_port, upper_dev,
4921e149113aSIdo Schimmel br_dev);
492256ade8feSJiri Pirko }
492356ade8feSJiri Pirko break;
492456ade8feSJiri Pirko }
492556ade8feSJiri Pirko
492680bedf1aSIdo Schimmel return err;
492756ade8feSJiri Pirko }
492856ade8feSJiri Pirko
mlxsw_sp_netdevice_port_lower_event(struct net_device * dev,unsigned long event,void * ptr)492974581206SJiri Pirko static int mlxsw_sp_netdevice_port_lower_event(struct net_device *dev,
493074581206SJiri Pirko unsigned long event, void *ptr)
493174581206SJiri Pirko {
493274581206SJiri Pirko struct netdev_notifier_changelowerstate_info *info;
493374581206SJiri Pirko struct mlxsw_sp_port *mlxsw_sp_port;
493474581206SJiri Pirko int err;
493574581206SJiri Pirko
493674581206SJiri Pirko mlxsw_sp_port = netdev_priv(dev);
493774581206SJiri Pirko info = ptr;
493874581206SJiri Pirko
493974581206SJiri Pirko switch (event) {
494074581206SJiri Pirko case NETDEV_CHANGELOWERSTATE:
494174581206SJiri Pirko if (netif_is_lag_port(dev) && mlxsw_sp_port->lagged) {
494274581206SJiri Pirko err = mlxsw_sp_port_lag_changed(mlxsw_sp_port,
494374581206SJiri Pirko info->lower_state_info);
494474581206SJiri Pirko if (err)
494574581206SJiri Pirko netdev_err(dev, "Failed to reflect link aggregation lower state change\n");
494674581206SJiri Pirko }
494774581206SJiri Pirko break;
494874581206SJiri Pirko }
494974581206SJiri Pirko
495080bedf1aSIdo Schimmel return 0;
495174581206SJiri Pirko }
495274581206SJiri Pirko
mlxsw_sp_netdevice_port_event(struct net_device * lower_dev,struct net_device * port_dev,unsigned long event,void * ptr,bool replay_deslavement)4953f0cebd81SIdo Schimmel static int mlxsw_sp_netdevice_port_event(struct net_device *lower_dev,
4954f0cebd81SIdo Schimmel struct net_device *port_dev,
49551c47e65bSPetr Machata unsigned long event, void *ptr,
49561c47e65bSPetr Machata bool replay_deslavement)
495774581206SJiri Pirko {
495874581206SJiri Pirko switch (event) {
495974581206SJiri Pirko case NETDEV_PRECHANGEUPPER:
496074581206SJiri Pirko case NETDEV_CHANGEUPPER:
4961f0cebd81SIdo Schimmel return mlxsw_sp_netdevice_port_upper_event(lower_dev, port_dev,
49621c47e65bSPetr Machata event, ptr,
49631c47e65bSPetr Machata replay_deslavement);
496474581206SJiri Pirko case NETDEV_CHANGELOWERSTATE:
4965f0cebd81SIdo Schimmel return mlxsw_sp_netdevice_port_lower_event(port_dev, event,
4966f0cebd81SIdo Schimmel ptr);
496774581206SJiri Pirko }
496874581206SJiri Pirko
496980bedf1aSIdo Schimmel return 0;
497074581206SJiri Pirko }
497174581206SJiri Pirko
49724560cf40SPetr Machata /* Called for LAG or its upper VLAN after the per-LAG-lower processing was done,
49734560cf40SPetr Machata * to do any per-LAG / per-LAG-upper processing.
49744560cf40SPetr Machata */
mlxsw_sp_netdevice_post_lag_event(struct net_device * dev,unsigned long event,void * ptr)49754560cf40SPetr Machata static int mlxsw_sp_netdevice_post_lag_event(struct net_device *dev,
49764560cf40SPetr Machata unsigned long event,
49774560cf40SPetr Machata void *ptr)
49784560cf40SPetr Machata {
49794560cf40SPetr Machata struct mlxsw_sp *mlxsw_sp = mlxsw_sp_lower_get(dev);
49804560cf40SPetr Machata struct netdev_notifier_changeupper_info *info = ptr;
49814560cf40SPetr Machata
49824560cf40SPetr Machata if (!mlxsw_sp)
49834560cf40SPetr Machata return 0;
49844560cf40SPetr Machata
49854560cf40SPetr Machata switch (event) {
49864560cf40SPetr Machata case NETDEV_CHANGEUPPER:
49874560cf40SPetr Machata if (info->linking)
49884560cf40SPetr Machata break;
49894560cf40SPetr Machata if (netif_is_bridge_master(info->upper_dev))
49904560cf40SPetr Machata mlxsw_sp_netdevice_deslavement_replay(mlxsw_sp, dev);
49914560cf40SPetr Machata break;
49924560cf40SPetr Machata }
49934560cf40SPetr Machata return 0;
49944560cf40SPetr Machata }
49954560cf40SPetr Machata
mlxsw_sp_netdevice_lag_event(struct net_device * lag_dev,unsigned long event,void * ptr)49960d65fc13SJiri Pirko static int mlxsw_sp_netdevice_lag_event(struct net_device *lag_dev,
49970d65fc13SJiri Pirko unsigned long event, void *ptr)
49980d65fc13SJiri Pirko {
49990d65fc13SJiri Pirko struct net_device *dev;
50000d65fc13SJiri Pirko struct list_head *iter;
50010d65fc13SJiri Pirko int ret;
50020d65fc13SJiri Pirko
50030d65fc13SJiri Pirko netdev_for_each_lower_dev(lag_dev, dev, iter) {
50040d65fc13SJiri Pirko if (mlxsw_sp_port_dev_check(dev)) {
5005f0cebd81SIdo Schimmel ret = mlxsw_sp_netdevice_port_event(lag_dev, dev, event,
50061c47e65bSPetr Machata ptr, false);
500780bedf1aSIdo Schimmel if (ret)
50080d65fc13SJiri Pirko return ret;
50090d65fc13SJiri Pirko }
50100d65fc13SJiri Pirko }
50110d65fc13SJiri Pirko
50124560cf40SPetr Machata return mlxsw_sp_netdevice_post_lag_event(lag_dev, event, ptr);
50130d65fc13SJiri Pirko }
50140d65fc13SJiri Pirko
mlxsw_sp_netdevice_port_vlan_event(struct net_device * vlan_dev,struct net_device * dev,unsigned long event,void * ptr,u16 vid,bool replay_deslavement)5015f0cebd81SIdo Schimmel static int mlxsw_sp_netdevice_port_vlan_event(struct net_device *vlan_dev,
5016f0cebd81SIdo Schimmel struct net_device *dev,
501726f0e7fbSIdo Schimmel unsigned long event, void *ptr,
50181c47e65bSPetr Machata u16 vid, bool replay_deslavement)
501926f0e7fbSIdo Schimmel {
502026f0e7fbSIdo Schimmel struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(dev);
502190045fc9SIdo Schimmel struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
502226f0e7fbSIdo Schimmel struct netdev_notifier_changeupper_info *info = ptr;
5023c1f2c6d0SIdo Schimmel struct netlink_ext_ack *extack;
502426f0e7fbSIdo Schimmel struct net_device *upper_dev;
502580bedf1aSIdo Schimmel int err = 0;
502626f0e7fbSIdo Schimmel
5027c1f2c6d0SIdo Schimmel extack = netdev_notifier_info_to_extack(&info->info);
5028c1f2c6d0SIdo Schimmel
502926f0e7fbSIdo Schimmel switch (event) {
503026f0e7fbSIdo Schimmel case NETDEV_PRECHANGEUPPER:
503126f0e7fbSIdo Schimmel upper_dev = info->upper_dev;
5032c5516185SIdo Schimmel if (!netif_is_bridge_master(upper_dev) &&
50337cf0f96dSPetr Machata !netif_is_macvlan(upper_dev) &&
50347cf0f96dSPetr Machata !netif_is_l3_master(upper_dev)) {
5035c5516185SIdo Schimmel NL_SET_ERR_MSG_MOD(extack, "Unknown upper device type");
503680bedf1aSIdo Schimmel return -EINVAL;
5037c1f2c6d0SIdo Schimmel }
503825cc72a3SIdo Schimmel if (!info->linking)
503925cc72a3SIdo Schimmel break;
50401c30d183SIdo Schimmel if (netif_is_bridge_master(upper_dev) &&
50411c30d183SIdo Schimmel !mlxsw_sp_bridge_device_is_offloaded(mlxsw_sp, upper_dev) &&
50421c30d183SIdo Schimmel mlxsw_sp_bridge_has_vxlan(upper_dev) &&
50431c30d183SIdo Schimmel !mlxsw_sp_bridge_vxlan_is_valid(upper_dev, extack))
50441c30d183SIdo Schimmel return -EOPNOTSUPP;
504590045fc9SIdo Schimmel if (netdev_has_any_upper_dev(upper_dev) &&
504690045fc9SIdo Schimmel (!netif_is_bridge_master(upper_dev) ||
504790045fc9SIdo Schimmel !mlxsw_sp_bridge_device_is_offloaded(mlxsw_sp,
504890045fc9SIdo Schimmel upper_dev))) {
5049*2c5ffe8dSPetr Machata err = mlxsw_sp_netdevice_validate_uppers(mlxsw_sp,
5050*2c5ffe8dSPetr Machata upper_dev,
5051*2c5ffe8dSPetr Machata extack);
5052*2c5ffe8dSPetr Machata if (err)
5053*2c5ffe8dSPetr Machata return err;
5054c1f2c6d0SIdo Schimmel }
505526f0e7fbSIdo Schimmel break;
505626f0e7fbSIdo Schimmel case NETDEV_CHANGEUPPER:
505726f0e7fbSIdo Schimmel upper_dev = info->upper_dev;
50581f88061eSIdo Schimmel if (netif_is_bridge_master(upper_dev)) {
50594560cf40SPetr Machata if (info->linking) {
5060c57529e1SIdo Schimmel err = mlxsw_sp_port_bridge_join(mlxsw_sp_port,
5061f0cebd81SIdo Schimmel vlan_dev,
50629b63ef88SIdo Schimmel upper_dev,
50639b63ef88SIdo Schimmel extack);
50644560cf40SPetr Machata } else {
5065c57529e1SIdo Schimmel mlxsw_sp_port_bridge_leave(mlxsw_sp_port,
5066f0cebd81SIdo Schimmel vlan_dev,
5067f0cebd81SIdo Schimmel upper_dev);
50684560cf40SPetr Machata if (!replay_deslavement)
50694560cf40SPetr Machata break;
50704560cf40SPetr Machata mlxsw_sp_netdevice_deslavement_replay(mlxsw_sp,
50714560cf40SPetr Machata vlan_dev);
50724560cf40SPetr Machata }
50732db99378SIdo Schimmel } else if (netif_is_macvlan(upper_dev)) {
50742db99378SIdo Schimmel if (!info->linking)
50752db99378SIdo Schimmel mlxsw_sp_rif_macvlan_del(mlxsw_sp, upper_dev);
507626f0e7fbSIdo Schimmel }
50771f88061eSIdo Schimmel break;
507826f0e7fbSIdo Schimmel }
507926f0e7fbSIdo Schimmel
508080bedf1aSIdo Schimmel return err;
508126f0e7fbSIdo Schimmel }
508226f0e7fbSIdo Schimmel
mlxsw_sp_netdevice_lag_port_vlan_event(struct net_device * vlan_dev,struct net_device * lag_dev,unsigned long event,void * ptr,u16 vid)5083f0cebd81SIdo Schimmel static int mlxsw_sp_netdevice_lag_port_vlan_event(struct net_device *vlan_dev,
5084f0cebd81SIdo Schimmel struct net_device *lag_dev,
5085f0cebd81SIdo Schimmel unsigned long event,
5086f0cebd81SIdo Schimmel void *ptr, u16 vid)
5087272c4470SIdo Schimmel {
5088272c4470SIdo Schimmel struct net_device *dev;
5089272c4470SIdo Schimmel struct list_head *iter;
5090272c4470SIdo Schimmel int ret;
5091272c4470SIdo Schimmel
5092272c4470SIdo Schimmel netdev_for_each_lower_dev(lag_dev, dev, iter) {
5093272c4470SIdo Schimmel if (mlxsw_sp_port_dev_check(dev)) {
5094f0cebd81SIdo Schimmel ret = mlxsw_sp_netdevice_port_vlan_event(vlan_dev, dev,
5095f0cebd81SIdo Schimmel event, ptr,
50961c47e65bSPetr Machata vid, false);
509780bedf1aSIdo Schimmel if (ret)
5098272c4470SIdo Schimmel return ret;
5099272c4470SIdo Schimmel }
5100272c4470SIdo Schimmel }
5101272c4470SIdo Schimmel
51024560cf40SPetr Machata return mlxsw_sp_netdevice_post_lag_event(vlan_dev, event, ptr);
5103272c4470SIdo Schimmel }
5104272c4470SIdo Schimmel
mlxsw_sp_netdevice_bridge_vlan_event(struct mlxsw_sp * mlxsw_sp,struct net_device * vlan_dev,struct net_device * br_dev,unsigned long event,void * ptr,u16 vid,bool process_foreign)510540b7b423SPetr Machata static int mlxsw_sp_netdevice_bridge_vlan_event(struct mlxsw_sp *mlxsw_sp,
510640b7b423SPetr Machata struct net_device *vlan_dev,
5107927d0ef1SIdo Schimmel struct net_device *br_dev,
5108927d0ef1SIdo Schimmel unsigned long event, void *ptr,
510940b7b423SPetr Machata u16 vid, bool process_foreign)
5110927d0ef1SIdo Schimmel {
5111927d0ef1SIdo Schimmel struct netdev_notifier_changeupper_info *info = ptr;
5112927d0ef1SIdo Schimmel struct netlink_ext_ack *extack;
5113927d0ef1SIdo Schimmel struct net_device *upper_dev;
5114927d0ef1SIdo Schimmel
511540b7b423SPetr Machata if (!process_foreign && !mlxsw_sp_lower_get(vlan_dev))
5116927d0ef1SIdo Schimmel return 0;
5117927d0ef1SIdo Schimmel
5118927d0ef1SIdo Schimmel extack = netdev_notifier_info_to_extack(&info->info);
5119927d0ef1SIdo Schimmel
5120927d0ef1SIdo Schimmel switch (event) {
5121927d0ef1SIdo Schimmel case NETDEV_PRECHANGEUPPER:
5122927d0ef1SIdo Schimmel upper_dev = info->upper_dev;
51237cf0f96dSPetr Machata if (!netif_is_macvlan(upper_dev) &&
51247cf0f96dSPetr Machata !netif_is_l3_master(upper_dev)) {
5125927d0ef1SIdo Schimmel NL_SET_ERR_MSG_MOD(extack, "Unknown upper device type");
5126927d0ef1SIdo Schimmel return -EOPNOTSUPP;
5127927d0ef1SIdo Schimmel }
5128927d0ef1SIdo Schimmel break;
5129927d0ef1SIdo Schimmel case NETDEV_CHANGEUPPER:
5130927d0ef1SIdo Schimmel upper_dev = info->upper_dev;
5131927d0ef1SIdo Schimmel if (info->linking)
5132927d0ef1SIdo Schimmel break;
5133927d0ef1SIdo Schimmel if (netif_is_macvlan(upper_dev))
5134927d0ef1SIdo Schimmel mlxsw_sp_rif_macvlan_del(mlxsw_sp, upper_dev);
5135927d0ef1SIdo Schimmel break;
5136927d0ef1SIdo Schimmel }
5137927d0ef1SIdo Schimmel
5138927d0ef1SIdo Schimmel return 0;
5139927d0ef1SIdo Schimmel }
5140927d0ef1SIdo Schimmel
mlxsw_sp_netdevice_vlan_event(struct mlxsw_sp * mlxsw_sp,struct net_device * vlan_dev,unsigned long event,void * ptr,bool process_foreign)514140b7b423SPetr Machata static int mlxsw_sp_netdevice_vlan_event(struct mlxsw_sp *mlxsw_sp,
514240b7b423SPetr Machata struct net_device *vlan_dev,
514340b7b423SPetr Machata unsigned long event, void *ptr,
514440b7b423SPetr Machata bool process_foreign)
514526f0e7fbSIdo Schimmel {
514626f0e7fbSIdo Schimmel struct net_device *real_dev = vlan_dev_real_dev(vlan_dev);
514726f0e7fbSIdo Schimmel u16 vid = vlan_dev_vlan_id(vlan_dev);
514826f0e7fbSIdo Schimmel
5149272c4470SIdo Schimmel if (mlxsw_sp_port_dev_check(real_dev))
5150f0cebd81SIdo Schimmel return mlxsw_sp_netdevice_port_vlan_event(vlan_dev, real_dev,
51511c47e65bSPetr Machata event, ptr, vid,
51521c47e65bSPetr Machata true);
5153272c4470SIdo Schimmel else if (netif_is_lag_master(real_dev))
5154f0cebd81SIdo Schimmel return mlxsw_sp_netdevice_lag_port_vlan_event(vlan_dev,
5155f0cebd81SIdo Schimmel real_dev, event,
5156f0cebd81SIdo Schimmel ptr, vid);
5157927d0ef1SIdo Schimmel else if (netif_is_bridge_master(real_dev))
515840b7b423SPetr Machata return mlxsw_sp_netdevice_bridge_vlan_event(mlxsw_sp, vlan_dev,
515940b7b423SPetr Machata real_dev, event,
516040b7b423SPetr Machata ptr, vid,
516140b7b423SPetr Machata process_foreign);
516226f0e7fbSIdo Schimmel
516380bedf1aSIdo Schimmel return 0;
516426f0e7fbSIdo Schimmel }
516526f0e7fbSIdo Schimmel
mlxsw_sp_netdevice_bridge_event(struct mlxsw_sp * mlxsw_sp,struct net_device * br_dev,unsigned long event,void * ptr,bool process_foreign)516640b7b423SPetr Machata static int mlxsw_sp_netdevice_bridge_event(struct mlxsw_sp *mlxsw_sp,
516740b7b423SPetr Machata struct net_device *br_dev,
516840b7b423SPetr Machata unsigned long event, void *ptr,
516940b7b423SPetr Machata bool process_foreign)
5170c5516185SIdo Schimmel {
5171c5516185SIdo Schimmel struct netdev_notifier_changeupper_info *info = ptr;
5172c5516185SIdo Schimmel struct netlink_ext_ack *extack;
5173c5516185SIdo Schimmel struct net_device *upper_dev;
517409139f67SDanielle Ratson u16 proto;
5175c5516185SIdo Schimmel
517640b7b423SPetr Machata if (!process_foreign && !mlxsw_sp_lower_get(br_dev))
5177c5516185SIdo Schimmel return 0;
5178c5516185SIdo Schimmel
5179c5516185SIdo Schimmel extack = netdev_notifier_info_to_extack(&info->info);
5180c5516185SIdo Schimmel
5181c5516185SIdo Schimmel switch (event) {
5182c5516185SIdo Schimmel case NETDEV_PRECHANGEUPPER:
5183c5516185SIdo Schimmel upper_dev = info->upper_dev;
51847cf0f96dSPetr Machata if (!is_vlan_dev(upper_dev) &&
51857cf0f96dSPetr Machata !netif_is_macvlan(upper_dev) &&
51867cf0f96dSPetr Machata !netif_is_l3_master(upper_dev)) {
5187c5516185SIdo Schimmel NL_SET_ERR_MSG_MOD(extack, "Unknown upper device type");
5188c5516185SIdo Schimmel return -EOPNOTSUPP;
5189c5516185SIdo Schimmel }
5190c5516185SIdo Schimmel if (!info->linking)
5191c5516185SIdo Schimmel break;
519209139f67SDanielle Ratson if (br_vlan_enabled(br_dev)) {
519309139f67SDanielle Ratson br_vlan_get_proto(br_dev, &proto);
519409139f67SDanielle Ratson if (proto == ETH_P_8021AD) {
5195825e8885SDanielle Ratson NL_SET_ERR_MSG_MOD(extack, "Upper devices are not supported on top of an 802.1ad bridge");
519609139f67SDanielle Ratson return -EOPNOTSUPP;
519709139f67SDanielle Ratson }
519809139f67SDanielle Ratson }
519909139f67SDanielle Ratson if (is_vlan_dev(upper_dev) &&
520009139f67SDanielle Ratson ntohs(vlan_dev_vlan_proto(upper_dev)) != ETH_P_8021Q) {
520109139f67SDanielle Ratson NL_SET_ERR_MSG_MOD(extack, "VLAN uppers are only supported with 802.1q VLAN protocol");
520209139f67SDanielle Ratson return -EOPNOTSUPP;
520309139f67SDanielle Ratson }
5204c5516185SIdo Schimmel break;
5205c5516185SIdo Schimmel case NETDEV_CHANGEUPPER:
52062db99378SIdo Schimmel upper_dev = info->upper_dev;
52072db99378SIdo Schimmel if (info->linking)
52082db99378SIdo Schimmel break;
5209c360867eSIdo Schimmel if (is_vlan_dev(upper_dev))
5210c360867eSIdo Schimmel mlxsw_sp_rif_destroy_by_dev(mlxsw_sp, upper_dev);
52112db99378SIdo Schimmel if (netif_is_macvlan(upper_dev))
52122db99378SIdo Schimmel mlxsw_sp_rif_macvlan_del(mlxsw_sp, upper_dev);
5213c5516185SIdo Schimmel break;
5214c5516185SIdo Schimmel }
5215c5516185SIdo Schimmel
5216c5516185SIdo Schimmel return 0;
5217c5516185SIdo Schimmel }
5218c5516185SIdo Schimmel
mlxsw_sp_netdevice_macvlan_event(struct net_device * macvlan_dev,unsigned long event,void * ptr)5219c5516185SIdo Schimmel static int mlxsw_sp_netdevice_macvlan_event(struct net_device *macvlan_dev,
5220c5516185SIdo Schimmel unsigned long event, void *ptr)
5221c5516185SIdo Schimmel {
5222c5516185SIdo Schimmel struct mlxsw_sp *mlxsw_sp = mlxsw_sp_lower_get(macvlan_dev);
5223c5516185SIdo Schimmel struct netdev_notifier_changeupper_info *info = ptr;
5224c5516185SIdo Schimmel struct netlink_ext_ack *extack;
52257cf0f96dSPetr Machata struct net_device *upper_dev;
5226c5516185SIdo Schimmel
5227c5516185SIdo Schimmel if (!mlxsw_sp || event != NETDEV_PRECHANGEUPPER)
5228c5516185SIdo Schimmel return 0;
5229c5516185SIdo Schimmel
5230c5516185SIdo Schimmel extack = netdev_notifier_info_to_extack(&info->info);
52317cf0f96dSPetr Machata upper_dev = info->upper_dev;
5232c5516185SIdo Schimmel
52337cf0f96dSPetr Machata if (!netif_is_l3_master(upper_dev)) {
5234c5516185SIdo Schimmel NL_SET_ERR_MSG_MOD(extack, "Unknown upper device type");
5235c5516185SIdo Schimmel return -EOPNOTSUPP;
5236c5516185SIdo Schimmel }
5237c5516185SIdo Schimmel
52387cf0f96dSPetr Machata return 0;
52397cf0f96dSPetr Machata }
52407cf0f96dSPetr Machata
mlxsw_sp_netdevice_vxlan_event(struct mlxsw_sp * mlxsw_sp,struct net_device * dev,unsigned long event,void * ptr)52411c30d183SIdo Schimmel static int mlxsw_sp_netdevice_vxlan_event(struct mlxsw_sp *mlxsw_sp,
52421c30d183SIdo Schimmel struct net_device *dev,
52431c30d183SIdo Schimmel unsigned long event, void *ptr)
52441c30d183SIdo Schimmel {
52451c30d183SIdo Schimmel struct netdev_notifier_changeupper_info *cu_info;
52461c30d183SIdo Schimmel struct netdev_notifier_info *info = ptr;
52471c30d183SIdo Schimmel struct netlink_ext_ack *extack;
52481c30d183SIdo Schimmel struct net_device *upper_dev;
52491c30d183SIdo Schimmel
52501c30d183SIdo Schimmel extack = netdev_notifier_info_to_extack(info);
52511c30d183SIdo Schimmel
52521c30d183SIdo Schimmel switch (event) {
52531c30d183SIdo Schimmel case NETDEV_CHANGEUPPER:
52541c30d183SIdo Schimmel cu_info = container_of(info,
52551c30d183SIdo Schimmel struct netdev_notifier_changeupper_info,
52561c30d183SIdo Schimmel info);
52571c30d183SIdo Schimmel upper_dev = cu_info->upper_dev;
52581c30d183SIdo Schimmel if (!netif_is_bridge_master(upper_dev))
52591c30d183SIdo Schimmel return 0;
52601c30d183SIdo Schimmel if (!mlxsw_sp_lower_get(upper_dev))
52611c30d183SIdo Schimmel return 0;
52621c30d183SIdo Schimmel if (!mlxsw_sp_bridge_vxlan_is_valid(upper_dev, extack))
52631c30d183SIdo Schimmel return -EOPNOTSUPP;
52641c30d183SIdo Schimmel if (cu_info->linking) {
52651c30d183SIdo Schimmel if (!netif_running(dev))
52661c30d183SIdo Schimmel return 0;
5267d70e42b2SIdo Schimmel /* When the bridge is VLAN-aware, the VNI of the VxLAN
5268d70e42b2SIdo Schimmel * device needs to be mapped to a VLAN, but at this
5269d70e42b2SIdo Schimmel * point no VLANs are configured on the VxLAN device
5270d70e42b2SIdo Schimmel */
5271d70e42b2SIdo Schimmel if (br_vlan_enabled(upper_dev))
5272d70e42b2SIdo Schimmel return 0;
52731c30d183SIdo Schimmel return mlxsw_sp_bridge_vxlan_join(mlxsw_sp, upper_dev,
527448fde466SIdo Schimmel dev, 0, extack);
52751c30d183SIdo Schimmel } else {
5276d70e42b2SIdo Schimmel /* VLANs were already flushed, which triggered the
5277d70e42b2SIdo Schimmel * necessary cleanup
5278d70e42b2SIdo Schimmel */
5279d70e42b2SIdo Schimmel if (br_vlan_enabled(upper_dev))
5280d70e42b2SIdo Schimmel return 0;
5281b03fa9e7SIdo Schimmel mlxsw_sp_bridge_vxlan_leave(mlxsw_sp, dev);
52821c30d183SIdo Schimmel }
52831c30d183SIdo Schimmel break;
52841c30d183SIdo Schimmel case NETDEV_PRE_UP:
52851c30d183SIdo Schimmel upper_dev = netdev_master_upper_dev_get(dev);
52861c30d183SIdo Schimmel if (!upper_dev)
52871c30d183SIdo Schimmel return 0;
52881c30d183SIdo Schimmel if (!netif_is_bridge_master(upper_dev))
52891c30d183SIdo Schimmel return 0;
52901c30d183SIdo Schimmel if (!mlxsw_sp_lower_get(upper_dev))
52911c30d183SIdo Schimmel return 0;
529248fde466SIdo Schimmel return mlxsw_sp_bridge_vxlan_join(mlxsw_sp, upper_dev, dev, 0,
52931c30d183SIdo Schimmel extack);
52941c30d183SIdo Schimmel case NETDEV_DOWN:
52951c30d183SIdo Schimmel upper_dev = netdev_master_upper_dev_get(dev);
52961c30d183SIdo Schimmel if (!upper_dev)
52971c30d183SIdo Schimmel return 0;
52981c30d183SIdo Schimmel if (!netif_is_bridge_master(upper_dev))
52991c30d183SIdo Schimmel return 0;
53001c30d183SIdo Schimmel if (!mlxsw_sp_lower_get(upper_dev))
53011c30d183SIdo Schimmel return 0;
5302b03fa9e7SIdo Schimmel mlxsw_sp_bridge_vxlan_leave(mlxsw_sp, dev);
53031c30d183SIdo Schimmel break;
53041c30d183SIdo Schimmel }
53051c30d183SIdo Schimmel
53061c30d183SIdo Schimmel return 0;
53071c30d183SIdo Schimmel }
53081c30d183SIdo Schimmel
__mlxsw_sp_netdevice_event(struct mlxsw_sp * mlxsw_sp,unsigned long event,void * ptr,bool process_foreign)5309721717faSPetr Machata static int __mlxsw_sp_netdevice_event(struct mlxsw_sp *mlxsw_sp,
531040b7b423SPetr Machata unsigned long event, void *ptr,
531140b7b423SPetr Machata bool process_foreign)
53120d65fc13SJiri Pirko {
53130d65fc13SJiri Pirko struct net_device *dev = netdev_notifier_info_to_dev(ptr);
5314079c9f39SPetr Machata struct mlxsw_sp_span_entry *span_entry;
531580bedf1aSIdo Schimmel int err = 0;
53160d65fc13SJiri Pirko
5317079c9f39SPetr Machata if (event == NETDEV_UNREGISTER) {
5318079c9f39SPetr Machata span_entry = mlxsw_sp_span_entry_find_by_port(mlxsw_sp, dev);
5319079c9f39SPetr Machata if (span_entry)
5320079c9f39SPetr Machata mlxsw_sp_span_entry_invalidate(mlxsw_sp, span_entry);
5321079c9f39SPetr Machata }
5322079c9f39SPetr Machata
53231c30d183SIdo Schimmel if (netif_is_vxlan(dev))
53241c30d183SIdo Schimmel err = mlxsw_sp_netdevice_vxlan_event(mlxsw_sp, dev, event, ptr);
53256e095fd4SIdo Schimmel else if (mlxsw_sp_port_dev_check(dev))
53261c47e65bSPetr Machata err = mlxsw_sp_netdevice_port_event(dev, dev, event, ptr, true);
532780bedf1aSIdo Schimmel else if (netif_is_lag_master(dev))
532880bedf1aSIdo Schimmel err = mlxsw_sp_netdevice_lag_event(dev, event, ptr);
532980bedf1aSIdo Schimmel else if (is_vlan_dev(dev))
533040b7b423SPetr Machata err = mlxsw_sp_netdevice_vlan_event(mlxsw_sp, dev, event, ptr,
533140b7b423SPetr Machata process_foreign);
5332c5516185SIdo Schimmel else if (netif_is_bridge_master(dev))
533340b7b423SPetr Machata err = mlxsw_sp_netdevice_bridge_event(mlxsw_sp, dev, event, ptr,
533440b7b423SPetr Machata process_foreign);
5335c5516185SIdo Schimmel else if (netif_is_macvlan(dev))
5336c5516185SIdo Schimmel err = mlxsw_sp_netdevice_macvlan_event(dev, event, ptr);
53370d65fc13SJiri Pirko
5338721717faSPetr Machata return err;
5339721717faSPetr Machata }
5340721717faSPetr Machata
mlxsw_sp_netdevice_event(struct notifier_block * nb,unsigned long event,void * ptr)5341721717faSPetr Machata static int mlxsw_sp_netdevice_event(struct notifier_block *nb,
5342721717faSPetr Machata unsigned long event, void *ptr)
5343721717faSPetr Machata {
5344721717faSPetr Machata struct mlxsw_sp *mlxsw_sp;
5345721717faSPetr Machata int err;
5346721717faSPetr Machata
5347721717faSPetr Machata mlxsw_sp = container_of(nb, struct mlxsw_sp, netdevice_nb);
5348721717faSPetr Machata mlxsw_sp_span_respin(mlxsw_sp);
534940b7b423SPetr Machata err = __mlxsw_sp_netdevice_event(mlxsw_sp, event, ptr, false);
5350721717faSPetr Machata
535180bedf1aSIdo Schimmel return notifier_from_errno(err);
53520d65fc13SJiri Pirko }
53530d65fc13SJiri Pirko
5354c3ab4354SJiri Pirko static const struct pci_device_id mlxsw_sp1_pci_id_table[] = {
53551d20d23cSJiri Pirko {PCI_VDEVICE(MELLANOX, PCI_DEVICE_ID_MELLANOX_SPECTRUM), 0},
53561d20d23cSJiri Pirko {0, },
53571d20d23cSJiri Pirko };
53581d20d23cSJiri Pirko
5359c3ab4354SJiri Pirko static struct pci_driver mlxsw_sp1_pci_driver = {
5360c3ab4354SJiri Pirko .name = mlxsw_sp1_driver_name,
5361c3ab4354SJiri Pirko .id_table = mlxsw_sp1_pci_id_table,
5362c3ab4354SJiri Pirko };
5363c3ab4354SJiri Pirko
5364c3ab4354SJiri Pirko static const struct pci_device_id mlxsw_sp2_pci_id_table[] = {
5365c3ab4354SJiri Pirko {PCI_VDEVICE(MELLANOX, PCI_DEVICE_ID_MELLANOX_SPECTRUM2), 0},
5366c3ab4354SJiri Pirko {0, },
5367c3ab4354SJiri Pirko };
5368c3ab4354SJiri Pirko
5369c3ab4354SJiri Pirko static struct pci_driver mlxsw_sp2_pci_driver = {
5370c3ab4354SJiri Pirko .name = mlxsw_sp2_driver_name,
5371c3ab4354SJiri Pirko .id_table = mlxsw_sp2_pci_id_table,
53721d20d23cSJiri Pirko };
53731d20d23cSJiri Pirko
5374da382875SJiri Pirko static const struct pci_device_id mlxsw_sp3_pci_id_table[] = {
5375da382875SJiri Pirko {PCI_VDEVICE(MELLANOX, PCI_DEVICE_ID_MELLANOX_SPECTRUM3), 0},
5376da382875SJiri Pirko {0, },
5377da382875SJiri Pirko };
5378da382875SJiri Pirko
5379da382875SJiri Pirko static struct pci_driver mlxsw_sp3_pci_driver = {
5380da382875SJiri Pirko .name = mlxsw_sp3_driver_name,
5381da382875SJiri Pirko .id_table = mlxsw_sp3_pci_id_table,
5382da382875SJiri Pirko };
5383da382875SJiri Pirko
538447354021SAmit Cohen static const struct pci_device_id mlxsw_sp4_pci_id_table[] = {
538547354021SAmit Cohen {PCI_VDEVICE(MELLANOX, PCI_DEVICE_ID_MELLANOX_SPECTRUM4), 0},
538647354021SAmit Cohen {0, },
538747354021SAmit Cohen };
538847354021SAmit Cohen
538947354021SAmit Cohen static struct pci_driver mlxsw_sp4_pci_driver = {
539047354021SAmit Cohen .name = mlxsw_sp4_driver_name,
539147354021SAmit Cohen .id_table = mlxsw_sp4_pci_id_table,
539247354021SAmit Cohen };
539347354021SAmit Cohen
mlxsw_sp_module_init(void)539456ade8feSJiri Pirko static int __init mlxsw_sp_module_init(void)
539556ade8feSJiri Pirko {
539656ade8feSJiri Pirko int err;
539756ade8feSJiri Pirko
5398c3ab4354SJiri Pirko err = mlxsw_core_driver_register(&mlxsw_sp1_driver);
539956ade8feSJiri Pirko if (err)
540041b2bd20SPetr Machata return err;
54011d20d23cSJiri Pirko
5402c3ab4354SJiri Pirko err = mlxsw_core_driver_register(&mlxsw_sp2_driver);
54031d20d23cSJiri Pirko if (err)
5404c3ab4354SJiri Pirko goto err_sp2_core_driver_register;
5405c3ab4354SJiri Pirko
5406da382875SJiri Pirko err = mlxsw_core_driver_register(&mlxsw_sp3_driver);
5407da382875SJiri Pirko if (err)
5408da382875SJiri Pirko goto err_sp3_core_driver_register;
5409da382875SJiri Pirko
541047354021SAmit Cohen err = mlxsw_core_driver_register(&mlxsw_sp4_driver);
541147354021SAmit Cohen if (err)
541247354021SAmit Cohen goto err_sp4_core_driver_register;
541347354021SAmit Cohen
5414c3ab4354SJiri Pirko err = mlxsw_pci_driver_register(&mlxsw_sp1_pci_driver);
5415c3ab4354SJiri Pirko if (err)
5416c3ab4354SJiri Pirko goto err_sp1_pci_driver_register;
5417c3ab4354SJiri Pirko
5418c3ab4354SJiri Pirko err = mlxsw_pci_driver_register(&mlxsw_sp2_pci_driver);
5419c3ab4354SJiri Pirko if (err)
5420c3ab4354SJiri Pirko goto err_sp2_pci_driver_register;
54211d20d23cSJiri Pirko
5422da382875SJiri Pirko err = mlxsw_pci_driver_register(&mlxsw_sp3_pci_driver);
5423da382875SJiri Pirko if (err)
5424da382875SJiri Pirko goto err_sp3_pci_driver_register;
5425da382875SJiri Pirko
542647354021SAmit Cohen err = mlxsw_pci_driver_register(&mlxsw_sp4_pci_driver);
542747354021SAmit Cohen if (err)
542847354021SAmit Cohen goto err_sp4_pci_driver_register;
542947354021SAmit Cohen
543056ade8feSJiri Pirko return 0;
543156ade8feSJiri Pirko
543247354021SAmit Cohen err_sp4_pci_driver_register:
543347354021SAmit Cohen mlxsw_pci_driver_unregister(&mlxsw_sp3_pci_driver);
5434da382875SJiri Pirko err_sp3_pci_driver_register:
5435da382875SJiri Pirko mlxsw_pci_driver_unregister(&mlxsw_sp2_pci_driver);
5436c3ab4354SJiri Pirko err_sp2_pci_driver_register:
543728fe7900SJiri Pirko mlxsw_pci_driver_unregister(&mlxsw_sp1_pci_driver);
5438c3ab4354SJiri Pirko err_sp1_pci_driver_register:
543947354021SAmit Cohen mlxsw_core_driver_unregister(&mlxsw_sp4_driver);
544047354021SAmit Cohen err_sp4_core_driver_register:
5441da382875SJiri Pirko mlxsw_core_driver_unregister(&mlxsw_sp3_driver);
5442da382875SJiri Pirko err_sp3_core_driver_register:
5443c3ab4354SJiri Pirko mlxsw_core_driver_unregister(&mlxsw_sp2_driver);
5444c3ab4354SJiri Pirko err_sp2_core_driver_register:
5445c3ab4354SJiri Pirko mlxsw_core_driver_unregister(&mlxsw_sp1_driver);
544656ade8feSJiri Pirko return err;
544756ade8feSJiri Pirko }
544856ade8feSJiri Pirko
mlxsw_sp_module_exit(void)544956ade8feSJiri Pirko static void __exit mlxsw_sp_module_exit(void)
545056ade8feSJiri Pirko {
545147354021SAmit Cohen mlxsw_pci_driver_unregister(&mlxsw_sp4_pci_driver);
5452da382875SJiri Pirko mlxsw_pci_driver_unregister(&mlxsw_sp3_pci_driver);
5453c3ab4354SJiri Pirko mlxsw_pci_driver_unregister(&mlxsw_sp2_pci_driver);
5454c3ab4354SJiri Pirko mlxsw_pci_driver_unregister(&mlxsw_sp1_pci_driver);
545547354021SAmit Cohen mlxsw_core_driver_unregister(&mlxsw_sp4_driver);
5456da382875SJiri Pirko mlxsw_core_driver_unregister(&mlxsw_sp3_driver);
5457c3ab4354SJiri Pirko mlxsw_core_driver_unregister(&mlxsw_sp2_driver);
5458c3ab4354SJiri Pirko mlxsw_core_driver_unregister(&mlxsw_sp1_driver);
545956ade8feSJiri Pirko }
546056ade8feSJiri Pirko
546156ade8feSJiri Pirko module_init(mlxsw_sp_module_init);
546256ade8feSJiri Pirko module_exit(mlxsw_sp_module_exit);
546356ade8feSJiri Pirko
546456ade8feSJiri Pirko MODULE_LICENSE("Dual BSD/GPL");
546556ade8feSJiri Pirko MODULE_AUTHOR("Jiri Pirko <jiri@mellanox.com>");
546656ade8feSJiri Pirko MODULE_DESCRIPTION("Mellanox Spectrum driver");
5467c3ab4354SJiri Pirko MODULE_DEVICE_TABLE(pci, mlxsw_sp1_pci_id_table);
5468c3ab4354SJiri Pirko MODULE_DEVICE_TABLE(pci, mlxsw_sp2_pci_id_table);
5469da382875SJiri Pirko MODULE_DEVICE_TABLE(pci, mlxsw_sp3_pci_id_table);
547047354021SAmit Cohen MODULE_DEVICE_TABLE(pci, mlxsw_sp4_pci_id_table);
5471abfd6182SJiri Pirko MODULE_FIRMWARE(MLXSW_SP1_FW_FILENAME);
5472a72afb68SIdo Schimmel MODULE_FIRMWARE(MLXSW_SP2_FW_FILENAME);
547334639fa3SPetr Machata MODULE_FIRMWARE(MLXSW_SP3_FW_FILENAME);
5474b217127eSJiri Pirko MODULE_FIRMWARE(MLXSW_SP_LINECARDS_INI_BUNDLE_FILENAME);
5475