18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0 28c2ecf20Sopenharmony_ci/* Copyright (c) 2015-2018 Mellanox Technologies. All rights reserved */ 38c2ecf20Sopenharmony_ci 48c2ecf20Sopenharmony_ci#include <linux/kernel.h> 58c2ecf20Sopenharmony_ci#include <linux/module.h> 68c2ecf20Sopenharmony_ci#include <linux/types.h> 78c2ecf20Sopenharmony_ci#include <linux/pci.h> 88c2ecf20Sopenharmony_ci#include <linux/netdevice.h> 98c2ecf20Sopenharmony_ci#include <linux/etherdevice.h> 108c2ecf20Sopenharmony_ci#include <linux/ethtool.h> 118c2ecf20Sopenharmony_ci#include <linux/slab.h> 128c2ecf20Sopenharmony_ci#include <linux/device.h> 138c2ecf20Sopenharmony_ci#include <linux/skbuff.h> 148c2ecf20Sopenharmony_ci#include <linux/if_vlan.h> 158c2ecf20Sopenharmony_ci#include <linux/if_bridge.h> 168c2ecf20Sopenharmony_ci#include <linux/workqueue.h> 178c2ecf20Sopenharmony_ci#include <linux/jiffies.h> 188c2ecf20Sopenharmony_ci#include <linux/bitops.h> 198c2ecf20Sopenharmony_ci#include <linux/list.h> 208c2ecf20Sopenharmony_ci#include <linux/notifier.h> 218c2ecf20Sopenharmony_ci#include <linux/dcbnl.h> 228c2ecf20Sopenharmony_ci#include <linux/inetdevice.h> 238c2ecf20Sopenharmony_ci#include <linux/netlink.h> 248c2ecf20Sopenharmony_ci#include <linux/jhash.h> 258c2ecf20Sopenharmony_ci#include <linux/log2.h> 268c2ecf20Sopenharmony_ci#include <net/switchdev.h> 278c2ecf20Sopenharmony_ci#include <net/pkt_cls.h> 288c2ecf20Sopenharmony_ci#include <net/netevent.h> 298c2ecf20Sopenharmony_ci#include <net/addrconf.h> 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_ci#include "spectrum.h" 328c2ecf20Sopenharmony_ci#include "pci.h" 338c2ecf20Sopenharmony_ci#include "core.h" 348c2ecf20Sopenharmony_ci#include "core_env.h" 358c2ecf20Sopenharmony_ci#include "reg.h" 368c2ecf20Sopenharmony_ci#include "port.h" 378c2ecf20Sopenharmony_ci#include "trap.h" 388c2ecf20Sopenharmony_ci#include "txheader.h" 398c2ecf20Sopenharmony_ci#include "spectrum_cnt.h" 408c2ecf20Sopenharmony_ci#include "spectrum_dpipe.h" 418c2ecf20Sopenharmony_ci#include "spectrum_acl_flex_actions.h" 428c2ecf20Sopenharmony_ci#include "spectrum_span.h" 438c2ecf20Sopenharmony_ci#include "spectrum_ptp.h" 448c2ecf20Sopenharmony_ci#include "spectrum_trap.h" 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_ci#define MLXSW_SP1_FWREV_MAJOR 13 478c2ecf20Sopenharmony_ci#define MLXSW_SP1_FWREV_MINOR 2008 488c2ecf20Sopenharmony_ci#define MLXSW_SP1_FWREV_SUBMINOR 1310 498c2ecf20Sopenharmony_ci#define MLXSW_SP1_FWREV_CAN_RESET_MINOR 1702 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_cistatic const struct mlxsw_fw_rev mlxsw_sp1_fw_rev = { 528c2ecf20Sopenharmony_ci .major = MLXSW_SP1_FWREV_MAJOR, 538c2ecf20Sopenharmony_ci .minor = MLXSW_SP1_FWREV_MINOR, 548c2ecf20Sopenharmony_ci .subminor = MLXSW_SP1_FWREV_SUBMINOR, 558c2ecf20Sopenharmony_ci .can_reset_minor = MLXSW_SP1_FWREV_CAN_RESET_MINOR, 568c2ecf20Sopenharmony_ci}; 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_ci#define MLXSW_SP1_FW_FILENAME \ 598c2ecf20Sopenharmony_ci "mellanox/mlxsw_spectrum-" __stringify(MLXSW_SP1_FWREV_MAJOR) \ 608c2ecf20Sopenharmony_ci "." __stringify(MLXSW_SP1_FWREV_MINOR) \ 618c2ecf20Sopenharmony_ci "." __stringify(MLXSW_SP1_FWREV_SUBMINOR) ".mfa2" 628c2ecf20Sopenharmony_ci 638c2ecf20Sopenharmony_ci#define MLXSW_SP2_FWREV_MAJOR 29 648c2ecf20Sopenharmony_ci#define MLXSW_SP2_FWREV_MINOR 2008 658c2ecf20Sopenharmony_ci#define MLXSW_SP2_FWREV_SUBMINOR 1310 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_cistatic const struct mlxsw_fw_rev mlxsw_sp2_fw_rev = { 688c2ecf20Sopenharmony_ci .major = MLXSW_SP2_FWREV_MAJOR, 698c2ecf20Sopenharmony_ci .minor = MLXSW_SP2_FWREV_MINOR, 708c2ecf20Sopenharmony_ci .subminor = MLXSW_SP2_FWREV_SUBMINOR, 718c2ecf20Sopenharmony_ci}; 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_ci#define MLXSW_SP2_FW_FILENAME \ 748c2ecf20Sopenharmony_ci "mellanox/mlxsw_spectrum2-" __stringify(MLXSW_SP2_FWREV_MAJOR) \ 758c2ecf20Sopenharmony_ci "." __stringify(MLXSW_SP2_FWREV_MINOR) \ 768c2ecf20Sopenharmony_ci "." __stringify(MLXSW_SP2_FWREV_SUBMINOR) ".mfa2" 778c2ecf20Sopenharmony_ci 788c2ecf20Sopenharmony_ci#define MLXSW_SP3_FWREV_MAJOR 30 798c2ecf20Sopenharmony_ci#define MLXSW_SP3_FWREV_MINOR 2008 808c2ecf20Sopenharmony_ci#define MLXSW_SP3_FWREV_SUBMINOR 1310 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_cistatic const struct mlxsw_fw_rev mlxsw_sp3_fw_rev = { 838c2ecf20Sopenharmony_ci .major = MLXSW_SP3_FWREV_MAJOR, 848c2ecf20Sopenharmony_ci .minor = MLXSW_SP3_FWREV_MINOR, 858c2ecf20Sopenharmony_ci .subminor = MLXSW_SP3_FWREV_SUBMINOR, 868c2ecf20Sopenharmony_ci}; 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_ci#define MLXSW_SP3_FW_FILENAME \ 898c2ecf20Sopenharmony_ci "mellanox/mlxsw_spectrum3-" __stringify(MLXSW_SP3_FWREV_MAJOR) \ 908c2ecf20Sopenharmony_ci "." __stringify(MLXSW_SP3_FWREV_MINOR) \ 918c2ecf20Sopenharmony_ci "." __stringify(MLXSW_SP3_FWREV_SUBMINOR) ".mfa2" 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_cistatic const char mlxsw_sp1_driver_name[] = "mlxsw_spectrum"; 948c2ecf20Sopenharmony_cistatic const char mlxsw_sp2_driver_name[] = "mlxsw_spectrum2"; 958c2ecf20Sopenharmony_cistatic const char mlxsw_sp3_driver_name[] = "mlxsw_spectrum3"; 968c2ecf20Sopenharmony_ci 978c2ecf20Sopenharmony_cistatic const unsigned char mlxsw_sp1_mac_mask[ETH_ALEN] = { 988c2ecf20Sopenharmony_ci 0xff, 0xff, 0xff, 0xff, 0xfc, 0x00 998c2ecf20Sopenharmony_ci}; 1008c2ecf20Sopenharmony_cistatic const unsigned char mlxsw_sp2_mac_mask[ETH_ALEN] = { 1018c2ecf20Sopenharmony_ci 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00 1028c2ecf20Sopenharmony_ci}; 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_ci/* tx_hdr_version 1058c2ecf20Sopenharmony_ci * Tx header version. 1068c2ecf20Sopenharmony_ci * Must be set to 1. 1078c2ecf20Sopenharmony_ci */ 1088c2ecf20Sopenharmony_ciMLXSW_ITEM32(tx, hdr, version, 0x00, 28, 4); 1098c2ecf20Sopenharmony_ci 1108c2ecf20Sopenharmony_ci/* tx_hdr_ctl 1118c2ecf20Sopenharmony_ci * Packet control type. 1128c2ecf20Sopenharmony_ci * 0 - Ethernet control (e.g. EMADs, LACP) 1138c2ecf20Sopenharmony_ci * 1 - Ethernet data 1148c2ecf20Sopenharmony_ci */ 1158c2ecf20Sopenharmony_ciMLXSW_ITEM32(tx, hdr, ctl, 0x00, 26, 2); 1168c2ecf20Sopenharmony_ci 1178c2ecf20Sopenharmony_ci/* tx_hdr_proto 1188c2ecf20Sopenharmony_ci * Packet protocol type. Must be set to 1 (Ethernet). 1198c2ecf20Sopenharmony_ci */ 1208c2ecf20Sopenharmony_ciMLXSW_ITEM32(tx, hdr, proto, 0x00, 21, 3); 1218c2ecf20Sopenharmony_ci 1228c2ecf20Sopenharmony_ci/* tx_hdr_rx_is_router 1238c2ecf20Sopenharmony_ci * Packet is sent from the router. Valid for data packets only. 1248c2ecf20Sopenharmony_ci */ 1258c2ecf20Sopenharmony_ciMLXSW_ITEM32(tx, hdr, rx_is_router, 0x00, 19, 1); 1268c2ecf20Sopenharmony_ci 1278c2ecf20Sopenharmony_ci/* tx_hdr_fid_valid 1288c2ecf20Sopenharmony_ci * Indicates if the 'fid' field is valid and should be used for 1298c2ecf20Sopenharmony_ci * forwarding lookup. Valid for data packets only. 1308c2ecf20Sopenharmony_ci */ 1318c2ecf20Sopenharmony_ciMLXSW_ITEM32(tx, hdr, fid_valid, 0x00, 16, 1); 1328c2ecf20Sopenharmony_ci 1338c2ecf20Sopenharmony_ci/* tx_hdr_swid 1348c2ecf20Sopenharmony_ci * Switch partition ID. Must be set to 0. 1358c2ecf20Sopenharmony_ci */ 1368c2ecf20Sopenharmony_ciMLXSW_ITEM32(tx, hdr, swid, 0x00, 12, 3); 1378c2ecf20Sopenharmony_ci 1388c2ecf20Sopenharmony_ci/* tx_hdr_control_tclass 1398c2ecf20Sopenharmony_ci * Indicates if the packet should use the control TClass and not one 1408c2ecf20Sopenharmony_ci * of the data TClasses. 1418c2ecf20Sopenharmony_ci */ 1428c2ecf20Sopenharmony_ciMLXSW_ITEM32(tx, hdr, control_tclass, 0x00, 6, 1); 1438c2ecf20Sopenharmony_ci 1448c2ecf20Sopenharmony_ci/* tx_hdr_etclass 1458c2ecf20Sopenharmony_ci * Egress TClass to be used on the egress device on the egress port. 1468c2ecf20Sopenharmony_ci */ 1478c2ecf20Sopenharmony_ciMLXSW_ITEM32(tx, hdr, etclass, 0x00, 0, 4); 1488c2ecf20Sopenharmony_ci 1498c2ecf20Sopenharmony_ci/* tx_hdr_port_mid 1508c2ecf20Sopenharmony_ci * Destination local port for unicast packets. 1518c2ecf20Sopenharmony_ci * Destination multicast ID for multicast packets. 1528c2ecf20Sopenharmony_ci * 1538c2ecf20Sopenharmony_ci * Control packets are directed to a specific egress port, while data 1548c2ecf20Sopenharmony_ci * packets are transmitted through the CPU port (0) into the switch partition, 1558c2ecf20Sopenharmony_ci * where forwarding rules are applied. 1568c2ecf20Sopenharmony_ci */ 1578c2ecf20Sopenharmony_ciMLXSW_ITEM32(tx, hdr, port_mid, 0x04, 16, 16); 1588c2ecf20Sopenharmony_ci 1598c2ecf20Sopenharmony_ci/* tx_hdr_fid 1608c2ecf20Sopenharmony_ci * Forwarding ID used for L2 forwarding lookup. Valid only if 'fid_valid' is 1618c2ecf20Sopenharmony_ci * set, otherwise calculated based on the packet's VID using VID to FID mapping. 1628c2ecf20Sopenharmony_ci * Valid for data packets only. 1638c2ecf20Sopenharmony_ci */ 1648c2ecf20Sopenharmony_ciMLXSW_ITEM32(tx, hdr, fid, 0x08, 0, 16); 1658c2ecf20Sopenharmony_ci 1668c2ecf20Sopenharmony_ci/* tx_hdr_type 1678c2ecf20Sopenharmony_ci * 0 - Data packets 1688c2ecf20Sopenharmony_ci * 6 - Control packets 1698c2ecf20Sopenharmony_ci */ 1708c2ecf20Sopenharmony_ciMLXSW_ITEM32(tx, hdr, type, 0x0C, 0, 4); 1718c2ecf20Sopenharmony_ci 1728c2ecf20Sopenharmony_ciint mlxsw_sp_flow_counter_get(struct mlxsw_sp *mlxsw_sp, 1738c2ecf20Sopenharmony_ci unsigned int counter_index, u64 *packets, 1748c2ecf20Sopenharmony_ci u64 *bytes) 1758c2ecf20Sopenharmony_ci{ 1768c2ecf20Sopenharmony_ci char mgpc_pl[MLXSW_REG_MGPC_LEN]; 1778c2ecf20Sopenharmony_ci int err; 1788c2ecf20Sopenharmony_ci 1798c2ecf20Sopenharmony_ci mlxsw_reg_mgpc_pack(mgpc_pl, counter_index, MLXSW_REG_MGPC_OPCODE_NOP, 1808c2ecf20Sopenharmony_ci MLXSW_REG_FLOW_COUNTER_SET_TYPE_PACKETS_BYTES); 1818c2ecf20Sopenharmony_ci err = mlxsw_reg_query(mlxsw_sp->core, MLXSW_REG(mgpc), mgpc_pl); 1828c2ecf20Sopenharmony_ci if (err) 1838c2ecf20Sopenharmony_ci return err; 1848c2ecf20Sopenharmony_ci if (packets) 1858c2ecf20Sopenharmony_ci *packets = mlxsw_reg_mgpc_packet_counter_get(mgpc_pl); 1868c2ecf20Sopenharmony_ci if (bytes) 1878c2ecf20Sopenharmony_ci *bytes = mlxsw_reg_mgpc_byte_counter_get(mgpc_pl); 1888c2ecf20Sopenharmony_ci return 0; 1898c2ecf20Sopenharmony_ci} 1908c2ecf20Sopenharmony_ci 1918c2ecf20Sopenharmony_cistatic int mlxsw_sp_flow_counter_clear(struct mlxsw_sp *mlxsw_sp, 1928c2ecf20Sopenharmony_ci unsigned int counter_index) 1938c2ecf20Sopenharmony_ci{ 1948c2ecf20Sopenharmony_ci char mgpc_pl[MLXSW_REG_MGPC_LEN]; 1958c2ecf20Sopenharmony_ci 1968c2ecf20Sopenharmony_ci mlxsw_reg_mgpc_pack(mgpc_pl, counter_index, MLXSW_REG_MGPC_OPCODE_CLEAR, 1978c2ecf20Sopenharmony_ci MLXSW_REG_FLOW_COUNTER_SET_TYPE_PACKETS_BYTES); 1988c2ecf20Sopenharmony_ci return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(mgpc), mgpc_pl); 1998c2ecf20Sopenharmony_ci} 2008c2ecf20Sopenharmony_ci 2018c2ecf20Sopenharmony_ciint mlxsw_sp_flow_counter_alloc(struct mlxsw_sp *mlxsw_sp, 2028c2ecf20Sopenharmony_ci unsigned int *p_counter_index) 2038c2ecf20Sopenharmony_ci{ 2048c2ecf20Sopenharmony_ci int err; 2058c2ecf20Sopenharmony_ci 2068c2ecf20Sopenharmony_ci err = mlxsw_sp_counter_alloc(mlxsw_sp, MLXSW_SP_COUNTER_SUB_POOL_FLOW, 2078c2ecf20Sopenharmony_ci p_counter_index); 2088c2ecf20Sopenharmony_ci if (err) 2098c2ecf20Sopenharmony_ci return err; 2108c2ecf20Sopenharmony_ci err = mlxsw_sp_flow_counter_clear(mlxsw_sp, *p_counter_index); 2118c2ecf20Sopenharmony_ci if (err) 2128c2ecf20Sopenharmony_ci goto err_counter_clear; 2138c2ecf20Sopenharmony_ci return 0; 2148c2ecf20Sopenharmony_ci 2158c2ecf20Sopenharmony_cierr_counter_clear: 2168c2ecf20Sopenharmony_ci mlxsw_sp_counter_free(mlxsw_sp, MLXSW_SP_COUNTER_SUB_POOL_FLOW, 2178c2ecf20Sopenharmony_ci *p_counter_index); 2188c2ecf20Sopenharmony_ci return err; 2198c2ecf20Sopenharmony_ci} 2208c2ecf20Sopenharmony_ci 2218c2ecf20Sopenharmony_civoid mlxsw_sp_flow_counter_free(struct mlxsw_sp *mlxsw_sp, 2228c2ecf20Sopenharmony_ci unsigned int counter_index) 2238c2ecf20Sopenharmony_ci{ 2248c2ecf20Sopenharmony_ci mlxsw_sp_counter_free(mlxsw_sp, MLXSW_SP_COUNTER_SUB_POOL_FLOW, 2258c2ecf20Sopenharmony_ci counter_index); 2268c2ecf20Sopenharmony_ci} 2278c2ecf20Sopenharmony_ci 2288c2ecf20Sopenharmony_cistatic void mlxsw_sp_txhdr_construct(struct sk_buff *skb, 2298c2ecf20Sopenharmony_ci const struct mlxsw_tx_info *tx_info) 2308c2ecf20Sopenharmony_ci{ 2318c2ecf20Sopenharmony_ci char *txhdr = skb_push(skb, MLXSW_TXHDR_LEN); 2328c2ecf20Sopenharmony_ci 2338c2ecf20Sopenharmony_ci memset(txhdr, 0, MLXSW_TXHDR_LEN); 2348c2ecf20Sopenharmony_ci 2358c2ecf20Sopenharmony_ci mlxsw_tx_hdr_version_set(txhdr, MLXSW_TXHDR_VERSION_1); 2368c2ecf20Sopenharmony_ci mlxsw_tx_hdr_ctl_set(txhdr, MLXSW_TXHDR_ETH_CTL); 2378c2ecf20Sopenharmony_ci mlxsw_tx_hdr_proto_set(txhdr, MLXSW_TXHDR_PROTO_ETH); 2388c2ecf20Sopenharmony_ci mlxsw_tx_hdr_swid_set(txhdr, 0); 2398c2ecf20Sopenharmony_ci mlxsw_tx_hdr_control_tclass_set(txhdr, 1); 2408c2ecf20Sopenharmony_ci mlxsw_tx_hdr_port_mid_set(txhdr, tx_info->local_port); 2418c2ecf20Sopenharmony_ci mlxsw_tx_hdr_type_set(txhdr, MLXSW_TXHDR_TYPE_CONTROL); 2428c2ecf20Sopenharmony_ci} 2438c2ecf20Sopenharmony_ci 2448c2ecf20Sopenharmony_cienum mlxsw_reg_spms_state mlxsw_sp_stp_spms_state(u8 state) 2458c2ecf20Sopenharmony_ci{ 2468c2ecf20Sopenharmony_ci switch (state) { 2478c2ecf20Sopenharmony_ci case BR_STATE_FORWARDING: 2488c2ecf20Sopenharmony_ci return MLXSW_REG_SPMS_STATE_FORWARDING; 2498c2ecf20Sopenharmony_ci case BR_STATE_LEARNING: 2508c2ecf20Sopenharmony_ci return MLXSW_REG_SPMS_STATE_LEARNING; 2518c2ecf20Sopenharmony_ci case BR_STATE_LISTENING: 2528c2ecf20Sopenharmony_ci case BR_STATE_DISABLED: 2538c2ecf20Sopenharmony_ci case BR_STATE_BLOCKING: 2548c2ecf20Sopenharmony_ci return MLXSW_REG_SPMS_STATE_DISCARDING; 2558c2ecf20Sopenharmony_ci default: 2568c2ecf20Sopenharmony_ci BUG(); 2578c2ecf20Sopenharmony_ci } 2588c2ecf20Sopenharmony_ci} 2598c2ecf20Sopenharmony_ci 2608c2ecf20Sopenharmony_ciint mlxsw_sp_port_vid_stp_set(struct mlxsw_sp_port *mlxsw_sp_port, u16 vid, 2618c2ecf20Sopenharmony_ci u8 state) 2628c2ecf20Sopenharmony_ci{ 2638c2ecf20Sopenharmony_ci enum mlxsw_reg_spms_state spms_state = mlxsw_sp_stp_spms_state(state); 2648c2ecf20Sopenharmony_ci struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; 2658c2ecf20Sopenharmony_ci char *spms_pl; 2668c2ecf20Sopenharmony_ci int err; 2678c2ecf20Sopenharmony_ci 2688c2ecf20Sopenharmony_ci spms_pl = kmalloc(MLXSW_REG_SPMS_LEN, GFP_KERNEL); 2698c2ecf20Sopenharmony_ci if (!spms_pl) 2708c2ecf20Sopenharmony_ci return -ENOMEM; 2718c2ecf20Sopenharmony_ci mlxsw_reg_spms_pack(spms_pl, mlxsw_sp_port->local_port); 2728c2ecf20Sopenharmony_ci mlxsw_reg_spms_vid_pack(spms_pl, vid, spms_state); 2738c2ecf20Sopenharmony_ci 2748c2ecf20Sopenharmony_ci err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(spms), spms_pl); 2758c2ecf20Sopenharmony_ci kfree(spms_pl); 2768c2ecf20Sopenharmony_ci return err; 2778c2ecf20Sopenharmony_ci} 2788c2ecf20Sopenharmony_ci 2798c2ecf20Sopenharmony_cistatic int mlxsw_sp_base_mac_get(struct mlxsw_sp *mlxsw_sp) 2808c2ecf20Sopenharmony_ci{ 2818c2ecf20Sopenharmony_ci char spad_pl[MLXSW_REG_SPAD_LEN] = {0}; 2828c2ecf20Sopenharmony_ci int err; 2838c2ecf20Sopenharmony_ci 2848c2ecf20Sopenharmony_ci err = mlxsw_reg_query(mlxsw_sp->core, MLXSW_REG(spad), spad_pl); 2858c2ecf20Sopenharmony_ci if (err) 2868c2ecf20Sopenharmony_ci return err; 2878c2ecf20Sopenharmony_ci mlxsw_reg_spad_base_mac_memcpy_from(spad_pl, mlxsw_sp->base_mac); 2888c2ecf20Sopenharmony_ci return 0; 2898c2ecf20Sopenharmony_ci} 2908c2ecf20Sopenharmony_ci 2918c2ecf20Sopenharmony_ciint mlxsw_sp_port_admin_status_set(struct mlxsw_sp_port *mlxsw_sp_port, 2928c2ecf20Sopenharmony_ci bool is_up) 2938c2ecf20Sopenharmony_ci{ 2948c2ecf20Sopenharmony_ci struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; 2958c2ecf20Sopenharmony_ci char paos_pl[MLXSW_REG_PAOS_LEN]; 2968c2ecf20Sopenharmony_ci 2978c2ecf20Sopenharmony_ci mlxsw_reg_paos_pack(paos_pl, mlxsw_sp_port->local_port, 2988c2ecf20Sopenharmony_ci is_up ? MLXSW_PORT_ADMIN_STATUS_UP : 2998c2ecf20Sopenharmony_ci MLXSW_PORT_ADMIN_STATUS_DOWN); 3008c2ecf20Sopenharmony_ci return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(paos), paos_pl); 3018c2ecf20Sopenharmony_ci} 3028c2ecf20Sopenharmony_ci 3038c2ecf20Sopenharmony_cistatic int mlxsw_sp_port_dev_addr_set(struct mlxsw_sp_port *mlxsw_sp_port, 3048c2ecf20Sopenharmony_ci unsigned char *addr) 3058c2ecf20Sopenharmony_ci{ 3068c2ecf20Sopenharmony_ci struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; 3078c2ecf20Sopenharmony_ci char ppad_pl[MLXSW_REG_PPAD_LEN]; 3088c2ecf20Sopenharmony_ci 3098c2ecf20Sopenharmony_ci mlxsw_reg_ppad_pack(ppad_pl, true, mlxsw_sp_port->local_port); 3108c2ecf20Sopenharmony_ci mlxsw_reg_ppad_mac_memcpy_to(ppad_pl, addr); 3118c2ecf20Sopenharmony_ci return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(ppad), ppad_pl); 3128c2ecf20Sopenharmony_ci} 3138c2ecf20Sopenharmony_ci 3148c2ecf20Sopenharmony_cistatic int mlxsw_sp_port_dev_addr_init(struct mlxsw_sp_port *mlxsw_sp_port) 3158c2ecf20Sopenharmony_ci{ 3168c2ecf20Sopenharmony_ci struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; 3178c2ecf20Sopenharmony_ci unsigned char *addr = mlxsw_sp_port->dev->dev_addr; 3188c2ecf20Sopenharmony_ci 3198c2ecf20Sopenharmony_ci ether_addr_copy(addr, mlxsw_sp->base_mac); 3208c2ecf20Sopenharmony_ci addr[ETH_ALEN - 1] += mlxsw_sp_port->local_port; 3218c2ecf20Sopenharmony_ci return mlxsw_sp_port_dev_addr_set(mlxsw_sp_port, addr); 3228c2ecf20Sopenharmony_ci} 3238c2ecf20Sopenharmony_ci 3248c2ecf20Sopenharmony_cistatic int mlxsw_sp_port_max_mtu_get(struct mlxsw_sp_port *mlxsw_sp_port, int *p_max_mtu) 3258c2ecf20Sopenharmony_ci{ 3268c2ecf20Sopenharmony_ci struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; 3278c2ecf20Sopenharmony_ci char pmtu_pl[MLXSW_REG_PMTU_LEN]; 3288c2ecf20Sopenharmony_ci int err; 3298c2ecf20Sopenharmony_ci 3308c2ecf20Sopenharmony_ci mlxsw_reg_pmtu_pack(pmtu_pl, mlxsw_sp_port->local_port, 0); 3318c2ecf20Sopenharmony_ci err = mlxsw_reg_query(mlxsw_sp->core, MLXSW_REG(pmtu), pmtu_pl); 3328c2ecf20Sopenharmony_ci if (err) 3338c2ecf20Sopenharmony_ci return err; 3348c2ecf20Sopenharmony_ci 3358c2ecf20Sopenharmony_ci *p_max_mtu = mlxsw_reg_pmtu_max_mtu_get(pmtu_pl); 3368c2ecf20Sopenharmony_ci return 0; 3378c2ecf20Sopenharmony_ci} 3388c2ecf20Sopenharmony_ci 3398c2ecf20Sopenharmony_cistatic int mlxsw_sp_port_mtu_set(struct mlxsw_sp_port *mlxsw_sp_port, u16 mtu) 3408c2ecf20Sopenharmony_ci{ 3418c2ecf20Sopenharmony_ci struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; 3428c2ecf20Sopenharmony_ci char pmtu_pl[MLXSW_REG_PMTU_LEN]; 3438c2ecf20Sopenharmony_ci 3448c2ecf20Sopenharmony_ci mtu += MLXSW_TXHDR_LEN + ETH_HLEN; 3458c2ecf20Sopenharmony_ci if (mtu > mlxsw_sp_port->max_mtu) 3468c2ecf20Sopenharmony_ci return -EINVAL; 3478c2ecf20Sopenharmony_ci 3488c2ecf20Sopenharmony_ci mlxsw_reg_pmtu_pack(pmtu_pl, mlxsw_sp_port->local_port, mtu); 3498c2ecf20Sopenharmony_ci return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(pmtu), pmtu_pl); 3508c2ecf20Sopenharmony_ci} 3518c2ecf20Sopenharmony_ci 3528c2ecf20Sopenharmony_cistatic int mlxsw_sp_port_swid_set(struct mlxsw_sp_port *mlxsw_sp_port, u8 swid) 3538c2ecf20Sopenharmony_ci{ 3548c2ecf20Sopenharmony_ci struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; 3558c2ecf20Sopenharmony_ci char pspa_pl[MLXSW_REG_PSPA_LEN]; 3568c2ecf20Sopenharmony_ci 3578c2ecf20Sopenharmony_ci mlxsw_reg_pspa_pack(pspa_pl, swid, mlxsw_sp_port->local_port); 3588c2ecf20Sopenharmony_ci return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(pspa), pspa_pl); 3598c2ecf20Sopenharmony_ci} 3608c2ecf20Sopenharmony_ci 3618c2ecf20Sopenharmony_ciint mlxsw_sp_port_vp_mode_set(struct mlxsw_sp_port *mlxsw_sp_port, bool enable) 3628c2ecf20Sopenharmony_ci{ 3638c2ecf20Sopenharmony_ci struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; 3648c2ecf20Sopenharmony_ci char svpe_pl[MLXSW_REG_SVPE_LEN]; 3658c2ecf20Sopenharmony_ci 3668c2ecf20Sopenharmony_ci mlxsw_reg_svpe_pack(svpe_pl, mlxsw_sp_port->local_port, enable); 3678c2ecf20Sopenharmony_ci return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(svpe), svpe_pl); 3688c2ecf20Sopenharmony_ci} 3698c2ecf20Sopenharmony_ci 3708c2ecf20Sopenharmony_ciint mlxsw_sp_port_vid_learning_set(struct mlxsw_sp_port *mlxsw_sp_port, u16 vid, 3718c2ecf20Sopenharmony_ci bool learn_enable) 3728c2ecf20Sopenharmony_ci{ 3738c2ecf20Sopenharmony_ci struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; 3748c2ecf20Sopenharmony_ci char *spvmlr_pl; 3758c2ecf20Sopenharmony_ci int err; 3768c2ecf20Sopenharmony_ci 3778c2ecf20Sopenharmony_ci spvmlr_pl = kmalloc(MLXSW_REG_SPVMLR_LEN, GFP_KERNEL); 3788c2ecf20Sopenharmony_ci if (!spvmlr_pl) 3798c2ecf20Sopenharmony_ci return -ENOMEM; 3808c2ecf20Sopenharmony_ci mlxsw_reg_spvmlr_pack(spvmlr_pl, mlxsw_sp_port->local_port, vid, vid, 3818c2ecf20Sopenharmony_ci learn_enable); 3828c2ecf20Sopenharmony_ci err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(spvmlr), spvmlr_pl); 3838c2ecf20Sopenharmony_ci kfree(spvmlr_pl); 3848c2ecf20Sopenharmony_ci return err; 3858c2ecf20Sopenharmony_ci} 3868c2ecf20Sopenharmony_ci 3878c2ecf20Sopenharmony_cistatic int __mlxsw_sp_port_pvid_set(struct mlxsw_sp_port *mlxsw_sp_port, 3888c2ecf20Sopenharmony_ci u16 vid) 3898c2ecf20Sopenharmony_ci{ 3908c2ecf20Sopenharmony_ci struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; 3918c2ecf20Sopenharmony_ci char spvid_pl[MLXSW_REG_SPVID_LEN]; 3928c2ecf20Sopenharmony_ci 3938c2ecf20Sopenharmony_ci mlxsw_reg_spvid_pack(spvid_pl, mlxsw_sp_port->local_port, vid); 3948c2ecf20Sopenharmony_ci return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(spvid), spvid_pl); 3958c2ecf20Sopenharmony_ci} 3968c2ecf20Sopenharmony_ci 3978c2ecf20Sopenharmony_cistatic int mlxsw_sp_port_allow_untagged_set(struct mlxsw_sp_port *mlxsw_sp_port, 3988c2ecf20Sopenharmony_ci bool allow) 3998c2ecf20Sopenharmony_ci{ 4008c2ecf20Sopenharmony_ci struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; 4018c2ecf20Sopenharmony_ci char spaft_pl[MLXSW_REG_SPAFT_LEN]; 4028c2ecf20Sopenharmony_ci 4038c2ecf20Sopenharmony_ci mlxsw_reg_spaft_pack(spaft_pl, mlxsw_sp_port->local_port, allow); 4048c2ecf20Sopenharmony_ci return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(spaft), spaft_pl); 4058c2ecf20Sopenharmony_ci} 4068c2ecf20Sopenharmony_ci 4078c2ecf20Sopenharmony_ciint mlxsw_sp_port_pvid_set(struct mlxsw_sp_port *mlxsw_sp_port, u16 vid) 4088c2ecf20Sopenharmony_ci{ 4098c2ecf20Sopenharmony_ci int err; 4108c2ecf20Sopenharmony_ci 4118c2ecf20Sopenharmony_ci if (!vid) { 4128c2ecf20Sopenharmony_ci err = mlxsw_sp_port_allow_untagged_set(mlxsw_sp_port, false); 4138c2ecf20Sopenharmony_ci if (err) 4148c2ecf20Sopenharmony_ci return err; 4158c2ecf20Sopenharmony_ci } else { 4168c2ecf20Sopenharmony_ci err = __mlxsw_sp_port_pvid_set(mlxsw_sp_port, vid); 4178c2ecf20Sopenharmony_ci if (err) 4188c2ecf20Sopenharmony_ci return err; 4198c2ecf20Sopenharmony_ci err = mlxsw_sp_port_allow_untagged_set(mlxsw_sp_port, true); 4208c2ecf20Sopenharmony_ci if (err) 4218c2ecf20Sopenharmony_ci goto err_port_allow_untagged_set; 4228c2ecf20Sopenharmony_ci } 4238c2ecf20Sopenharmony_ci 4248c2ecf20Sopenharmony_ci mlxsw_sp_port->pvid = vid; 4258c2ecf20Sopenharmony_ci return 0; 4268c2ecf20Sopenharmony_ci 4278c2ecf20Sopenharmony_cierr_port_allow_untagged_set: 4288c2ecf20Sopenharmony_ci __mlxsw_sp_port_pvid_set(mlxsw_sp_port, mlxsw_sp_port->pvid); 4298c2ecf20Sopenharmony_ci return err; 4308c2ecf20Sopenharmony_ci} 4318c2ecf20Sopenharmony_ci 4328c2ecf20Sopenharmony_cistatic int 4338c2ecf20Sopenharmony_cimlxsw_sp_port_system_port_mapping_set(struct mlxsw_sp_port *mlxsw_sp_port) 4348c2ecf20Sopenharmony_ci{ 4358c2ecf20Sopenharmony_ci struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; 4368c2ecf20Sopenharmony_ci char sspr_pl[MLXSW_REG_SSPR_LEN]; 4378c2ecf20Sopenharmony_ci 4388c2ecf20Sopenharmony_ci mlxsw_reg_sspr_pack(sspr_pl, mlxsw_sp_port->local_port); 4398c2ecf20Sopenharmony_ci return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(sspr), sspr_pl); 4408c2ecf20Sopenharmony_ci} 4418c2ecf20Sopenharmony_ci 4428c2ecf20Sopenharmony_cistatic int 4438c2ecf20Sopenharmony_cimlxsw_sp_port_module_info_get(struct mlxsw_sp *mlxsw_sp, u8 local_port, 4448c2ecf20Sopenharmony_ci struct mlxsw_sp_port_mapping *port_mapping) 4458c2ecf20Sopenharmony_ci{ 4468c2ecf20Sopenharmony_ci char pmlp_pl[MLXSW_REG_PMLP_LEN]; 4478c2ecf20Sopenharmony_ci bool separate_rxtx; 4488c2ecf20Sopenharmony_ci u8 module; 4498c2ecf20Sopenharmony_ci u8 width; 4508c2ecf20Sopenharmony_ci int err; 4518c2ecf20Sopenharmony_ci int i; 4528c2ecf20Sopenharmony_ci 4538c2ecf20Sopenharmony_ci mlxsw_reg_pmlp_pack(pmlp_pl, local_port); 4548c2ecf20Sopenharmony_ci err = mlxsw_reg_query(mlxsw_sp->core, MLXSW_REG(pmlp), pmlp_pl); 4558c2ecf20Sopenharmony_ci if (err) 4568c2ecf20Sopenharmony_ci return err; 4578c2ecf20Sopenharmony_ci module = mlxsw_reg_pmlp_module_get(pmlp_pl, 0); 4588c2ecf20Sopenharmony_ci width = mlxsw_reg_pmlp_width_get(pmlp_pl); 4598c2ecf20Sopenharmony_ci separate_rxtx = mlxsw_reg_pmlp_rxtx_get(pmlp_pl); 4608c2ecf20Sopenharmony_ci 4618c2ecf20Sopenharmony_ci if (width && !is_power_of_2(width)) { 4628c2ecf20Sopenharmony_ci dev_err(mlxsw_sp->bus_info->dev, "Port %d: Unsupported module config: width value is not power of 2\n", 4638c2ecf20Sopenharmony_ci local_port); 4648c2ecf20Sopenharmony_ci return -EINVAL; 4658c2ecf20Sopenharmony_ci } 4668c2ecf20Sopenharmony_ci 4678c2ecf20Sopenharmony_ci for (i = 0; i < width; i++) { 4688c2ecf20Sopenharmony_ci if (mlxsw_reg_pmlp_module_get(pmlp_pl, i) != module) { 4698c2ecf20Sopenharmony_ci dev_err(mlxsw_sp->bus_info->dev, "Port %d: Unsupported module config: contains multiple modules\n", 4708c2ecf20Sopenharmony_ci local_port); 4718c2ecf20Sopenharmony_ci return -EINVAL; 4728c2ecf20Sopenharmony_ci } 4738c2ecf20Sopenharmony_ci if (separate_rxtx && 4748c2ecf20Sopenharmony_ci mlxsw_reg_pmlp_tx_lane_get(pmlp_pl, i) != 4758c2ecf20Sopenharmony_ci mlxsw_reg_pmlp_rx_lane_get(pmlp_pl, i)) { 4768c2ecf20Sopenharmony_ci dev_err(mlxsw_sp->bus_info->dev, "Port %d: Unsupported module config: TX and RX lane numbers are different\n", 4778c2ecf20Sopenharmony_ci local_port); 4788c2ecf20Sopenharmony_ci return -EINVAL; 4798c2ecf20Sopenharmony_ci } 4808c2ecf20Sopenharmony_ci if (mlxsw_reg_pmlp_tx_lane_get(pmlp_pl, i) != i) { 4818c2ecf20Sopenharmony_ci dev_err(mlxsw_sp->bus_info->dev, "Port %d: Unsupported module config: TX and RX lane numbers are not sequential\n", 4828c2ecf20Sopenharmony_ci local_port); 4838c2ecf20Sopenharmony_ci return -EINVAL; 4848c2ecf20Sopenharmony_ci } 4858c2ecf20Sopenharmony_ci } 4868c2ecf20Sopenharmony_ci 4878c2ecf20Sopenharmony_ci port_mapping->module = module; 4888c2ecf20Sopenharmony_ci port_mapping->width = width; 4898c2ecf20Sopenharmony_ci port_mapping->lane = mlxsw_reg_pmlp_tx_lane_get(pmlp_pl, 0); 4908c2ecf20Sopenharmony_ci return 0; 4918c2ecf20Sopenharmony_ci} 4928c2ecf20Sopenharmony_ci 4938c2ecf20Sopenharmony_cistatic int mlxsw_sp_port_module_map(struct mlxsw_sp_port *mlxsw_sp_port) 4948c2ecf20Sopenharmony_ci{ 4958c2ecf20Sopenharmony_ci struct mlxsw_sp_port_mapping *port_mapping = &mlxsw_sp_port->mapping; 4968c2ecf20Sopenharmony_ci struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; 4978c2ecf20Sopenharmony_ci char pmlp_pl[MLXSW_REG_PMLP_LEN]; 4988c2ecf20Sopenharmony_ci int i; 4998c2ecf20Sopenharmony_ci 5008c2ecf20Sopenharmony_ci mlxsw_reg_pmlp_pack(pmlp_pl, mlxsw_sp_port->local_port); 5018c2ecf20Sopenharmony_ci mlxsw_reg_pmlp_width_set(pmlp_pl, port_mapping->width); 5028c2ecf20Sopenharmony_ci for (i = 0; i < port_mapping->width; i++) { 5038c2ecf20Sopenharmony_ci mlxsw_reg_pmlp_module_set(pmlp_pl, i, port_mapping->module); 5048c2ecf20Sopenharmony_ci mlxsw_reg_pmlp_tx_lane_set(pmlp_pl, i, port_mapping->lane + i); /* Rx & Tx */ 5058c2ecf20Sopenharmony_ci } 5068c2ecf20Sopenharmony_ci 5078c2ecf20Sopenharmony_ci return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(pmlp), pmlp_pl); 5088c2ecf20Sopenharmony_ci} 5098c2ecf20Sopenharmony_ci 5108c2ecf20Sopenharmony_cistatic int mlxsw_sp_port_module_unmap(struct mlxsw_sp_port *mlxsw_sp_port) 5118c2ecf20Sopenharmony_ci{ 5128c2ecf20Sopenharmony_ci struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; 5138c2ecf20Sopenharmony_ci char pmlp_pl[MLXSW_REG_PMLP_LEN]; 5148c2ecf20Sopenharmony_ci 5158c2ecf20Sopenharmony_ci mlxsw_reg_pmlp_pack(pmlp_pl, mlxsw_sp_port->local_port); 5168c2ecf20Sopenharmony_ci mlxsw_reg_pmlp_width_set(pmlp_pl, 0); 5178c2ecf20Sopenharmony_ci return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(pmlp), pmlp_pl); 5188c2ecf20Sopenharmony_ci} 5198c2ecf20Sopenharmony_ci 5208c2ecf20Sopenharmony_cistatic int mlxsw_sp_port_open(struct net_device *dev) 5218c2ecf20Sopenharmony_ci{ 5228c2ecf20Sopenharmony_ci struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(dev); 5238c2ecf20Sopenharmony_ci int err; 5248c2ecf20Sopenharmony_ci 5258c2ecf20Sopenharmony_ci err = mlxsw_sp_port_admin_status_set(mlxsw_sp_port, true); 5268c2ecf20Sopenharmony_ci if (err) 5278c2ecf20Sopenharmony_ci return err; 5288c2ecf20Sopenharmony_ci netif_start_queue(dev); 5298c2ecf20Sopenharmony_ci return 0; 5308c2ecf20Sopenharmony_ci} 5318c2ecf20Sopenharmony_ci 5328c2ecf20Sopenharmony_cistatic int mlxsw_sp_port_stop(struct net_device *dev) 5338c2ecf20Sopenharmony_ci{ 5348c2ecf20Sopenharmony_ci struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(dev); 5358c2ecf20Sopenharmony_ci 5368c2ecf20Sopenharmony_ci netif_stop_queue(dev); 5378c2ecf20Sopenharmony_ci return mlxsw_sp_port_admin_status_set(mlxsw_sp_port, false); 5388c2ecf20Sopenharmony_ci} 5398c2ecf20Sopenharmony_ci 5408c2ecf20Sopenharmony_cistatic netdev_tx_t mlxsw_sp_port_xmit(struct sk_buff *skb, 5418c2ecf20Sopenharmony_ci struct net_device *dev) 5428c2ecf20Sopenharmony_ci{ 5438c2ecf20Sopenharmony_ci struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(dev); 5448c2ecf20Sopenharmony_ci struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; 5458c2ecf20Sopenharmony_ci struct mlxsw_sp_port_pcpu_stats *pcpu_stats; 5468c2ecf20Sopenharmony_ci const struct mlxsw_tx_info tx_info = { 5478c2ecf20Sopenharmony_ci .local_port = mlxsw_sp_port->local_port, 5488c2ecf20Sopenharmony_ci .is_emad = false, 5498c2ecf20Sopenharmony_ci }; 5508c2ecf20Sopenharmony_ci u64 len; 5518c2ecf20Sopenharmony_ci int err; 5528c2ecf20Sopenharmony_ci 5538c2ecf20Sopenharmony_ci if (skb_cow_head(skb, MLXSW_TXHDR_LEN)) { 5548c2ecf20Sopenharmony_ci this_cpu_inc(mlxsw_sp_port->pcpu_stats->tx_dropped); 5558c2ecf20Sopenharmony_ci dev_kfree_skb_any(skb); 5568c2ecf20Sopenharmony_ci return NETDEV_TX_OK; 5578c2ecf20Sopenharmony_ci } 5588c2ecf20Sopenharmony_ci 5598c2ecf20Sopenharmony_ci memset(skb->cb, 0, sizeof(struct mlxsw_skb_cb)); 5608c2ecf20Sopenharmony_ci 5618c2ecf20Sopenharmony_ci if (mlxsw_core_skb_transmit_busy(mlxsw_sp->core, &tx_info)) 5628c2ecf20Sopenharmony_ci return NETDEV_TX_BUSY; 5638c2ecf20Sopenharmony_ci 5648c2ecf20Sopenharmony_ci if (eth_skb_pad(skb)) { 5658c2ecf20Sopenharmony_ci this_cpu_inc(mlxsw_sp_port->pcpu_stats->tx_dropped); 5668c2ecf20Sopenharmony_ci return NETDEV_TX_OK; 5678c2ecf20Sopenharmony_ci } 5688c2ecf20Sopenharmony_ci 5698c2ecf20Sopenharmony_ci mlxsw_sp_txhdr_construct(skb, &tx_info); 5708c2ecf20Sopenharmony_ci /* TX header is consumed by HW on the way so we shouldn't count its 5718c2ecf20Sopenharmony_ci * bytes as being sent. 5728c2ecf20Sopenharmony_ci */ 5738c2ecf20Sopenharmony_ci len = skb->len - MLXSW_TXHDR_LEN; 5748c2ecf20Sopenharmony_ci 5758c2ecf20Sopenharmony_ci /* Due to a race we might fail here because of a full queue. In that 5768c2ecf20Sopenharmony_ci * unlikely case we simply drop the packet. 5778c2ecf20Sopenharmony_ci */ 5788c2ecf20Sopenharmony_ci err = mlxsw_core_skb_transmit(mlxsw_sp->core, skb, &tx_info); 5798c2ecf20Sopenharmony_ci 5808c2ecf20Sopenharmony_ci if (!err) { 5818c2ecf20Sopenharmony_ci pcpu_stats = this_cpu_ptr(mlxsw_sp_port->pcpu_stats); 5828c2ecf20Sopenharmony_ci u64_stats_update_begin(&pcpu_stats->syncp); 5838c2ecf20Sopenharmony_ci pcpu_stats->tx_packets++; 5848c2ecf20Sopenharmony_ci pcpu_stats->tx_bytes += len; 5858c2ecf20Sopenharmony_ci u64_stats_update_end(&pcpu_stats->syncp); 5868c2ecf20Sopenharmony_ci } else { 5878c2ecf20Sopenharmony_ci this_cpu_inc(mlxsw_sp_port->pcpu_stats->tx_dropped); 5888c2ecf20Sopenharmony_ci dev_kfree_skb_any(skb); 5898c2ecf20Sopenharmony_ci } 5908c2ecf20Sopenharmony_ci return NETDEV_TX_OK; 5918c2ecf20Sopenharmony_ci} 5928c2ecf20Sopenharmony_ci 5938c2ecf20Sopenharmony_cistatic void mlxsw_sp_set_rx_mode(struct net_device *dev) 5948c2ecf20Sopenharmony_ci{ 5958c2ecf20Sopenharmony_ci} 5968c2ecf20Sopenharmony_ci 5978c2ecf20Sopenharmony_cistatic int mlxsw_sp_port_set_mac_address(struct net_device *dev, void *p) 5988c2ecf20Sopenharmony_ci{ 5998c2ecf20Sopenharmony_ci struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(dev); 6008c2ecf20Sopenharmony_ci struct sockaddr *addr = p; 6018c2ecf20Sopenharmony_ci int err; 6028c2ecf20Sopenharmony_ci 6038c2ecf20Sopenharmony_ci if (!is_valid_ether_addr(addr->sa_data)) 6048c2ecf20Sopenharmony_ci return -EADDRNOTAVAIL; 6058c2ecf20Sopenharmony_ci 6068c2ecf20Sopenharmony_ci err = mlxsw_sp_port_dev_addr_set(mlxsw_sp_port, addr->sa_data); 6078c2ecf20Sopenharmony_ci if (err) 6088c2ecf20Sopenharmony_ci return err; 6098c2ecf20Sopenharmony_ci memcpy(dev->dev_addr, addr->sa_data, dev->addr_len); 6108c2ecf20Sopenharmony_ci return 0; 6118c2ecf20Sopenharmony_ci} 6128c2ecf20Sopenharmony_ci 6138c2ecf20Sopenharmony_cistatic int mlxsw_sp_port_change_mtu(struct net_device *dev, int mtu) 6148c2ecf20Sopenharmony_ci{ 6158c2ecf20Sopenharmony_ci struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(dev); 6168c2ecf20Sopenharmony_ci struct mlxsw_sp_hdroom orig_hdroom; 6178c2ecf20Sopenharmony_ci struct mlxsw_sp_hdroom hdroom; 6188c2ecf20Sopenharmony_ci int err; 6198c2ecf20Sopenharmony_ci 6208c2ecf20Sopenharmony_ci orig_hdroom = *mlxsw_sp_port->hdroom; 6218c2ecf20Sopenharmony_ci 6228c2ecf20Sopenharmony_ci hdroom = orig_hdroom; 6238c2ecf20Sopenharmony_ci hdroom.mtu = mtu; 6248c2ecf20Sopenharmony_ci mlxsw_sp_hdroom_bufs_reset_sizes(mlxsw_sp_port, &hdroom); 6258c2ecf20Sopenharmony_ci 6268c2ecf20Sopenharmony_ci err = mlxsw_sp_hdroom_configure(mlxsw_sp_port, &hdroom); 6278c2ecf20Sopenharmony_ci if (err) { 6288c2ecf20Sopenharmony_ci netdev_err(dev, "Failed to configure port's headroom\n"); 6298c2ecf20Sopenharmony_ci return err; 6308c2ecf20Sopenharmony_ci } 6318c2ecf20Sopenharmony_ci 6328c2ecf20Sopenharmony_ci err = mlxsw_sp_port_mtu_set(mlxsw_sp_port, mtu); 6338c2ecf20Sopenharmony_ci if (err) 6348c2ecf20Sopenharmony_ci goto err_port_mtu_set; 6358c2ecf20Sopenharmony_ci dev->mtu = mtu; 6368c2ecf20Sopenharmony_ci return 0; 6378c2ecf20Sopenharmony_ci 6388c2ecf20Sopenharmony_cierr_port_mtu_set: 6398c2ecf20Sopenharmony_ci mlxsw_sp_hdroom_configure(mlxsw_sp_port, &orig_hdroom); 6408c2ecf20Sopenharmony_ci return err; 6418c2ecf20Sopenharmony_ci} 6428c2ecf20Sopenharmony_ci 6438c2ecf20Sopenharmony_cistatic int 6448c2ecf20Sopenharmony_cimlxsw_sp_port_get_sw_stats64(const struct net_device *dev, 6458c2ecf20Sopenharmony_ci struct rtnl_link_stats64 *stats) 6468c2ecf20Sopenharmony_ci{ 6478c2ecf20Sopenharmony_ci struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(dev); 6488c2ecf20Sopenharmony_ci struct mlxsw_sp_port_pcpu_stats *p; 6498c2ecf20Sopenharmony_ci u64 rx_packets, rx_bytes, tx_packets, tx_bytes; 6508c2ecf20Sopenharmony_ci u32 tx_dropped = 0; 6518c2ecf20Sopenharmony_ci unsigned int start; 6528c2ecf20Sopenharmony_ci int i; 6538c2ecf20Sopenharmony_ci 6548c2ecf20Sopenharmony_ci for_each_possible_cpu(i) { 6558c2ecf20Sopenharmony_ci p = per_cpu_ptr(mlxsw_sp_port->pcpu_stats, i); 6568c2ecf20Sopenharmony_ci do { 6578c2ecf20Sopenharmony_ci start = u64_stats_fetch_begin_irq(&p->syncp); 6588c2ecf20Sopenharmony_ci rx_packets = p->rx_packets; 6598c2ecf20Sopenharmony_ci rx_bytes = p->rx_bytes; 6608c2ecf20Sopenharmony_ci tx_packets = p->tx_packets; 6618c2ecf20Sopenharmony_ci tx_bytes = p->tx_bytes; 6628c2ecf20Sopenharmony_ci } while (u64_stats_fetch_retry_irq(&p->syncp, start)); 6638c2ecf20Sopenharmony_ci 6648c2ecf20Sopenharmony_ci stats->rx_packets += rx_packets; 6658c2ecf20Sopenharmony_ci stats->rx_bytes += rx_bytes; 6668c2ecf20Sopenharmony_ci stats->tx_packets += tx_packets; 6678c2ecf20Sopenharmony_ci stats->tx_bytes += tx_bytes; 6688c2ecf20Sopenharmony_ci /* tx_dropped is u32, updated without syncp protection. */ 6698c2ecf20Sopenharmony_ci tx_dropped += p->tx_dropped; 6708c2ecf20Sopenharmony_ci } 6718c2ecf20Sopenharmony_ci stats->tx_dropped = tx_dropped; 6728c2ecf20Sopenharmony_ci return 0; 6738c2ecf20Sopenharmony_ci} 6748c2ecf20Sopenharmony_ci 6758c2ecf20Sopenharmony_cistatic bool mlxsw_sp_port_has_offload_stats(const struct net_device *dev, int attr_id) 6768c2ecf20Sopenharmony_ci{ 6778c2ecf20Sopenharmony_ci switch (attr_id) { 6788c2ecf20Sopenharmony_ci case IFLA_OFFLOAD_XSTATS_CPU_HIT: 6798c2ecf20Sopenharmony_ci return true; 6808c2ecf20Sopenharmony_ci } 6818c2ecf20Sopenharmony_ci 6828c2ecf20Sopenharmony_ci return false; 6838c2ecf20Sopenharmony_ci} 6848c2ecf20Sopenharmony_ci 6858c2ecf20Sopenharmony_cistatic int mlxsw_sp_port_get_offload_stats(int attr_id, const struct net_device *dev, 6868c2ecf20Sopenharmony_ci void *sp) 6878c2ecf20Sopenharmony_ci{ 6888c2ecf20Sopenharmony_ci switch (attr_id) { 6898c2ecf20Sopenharmony_ci case IFLA_OFFLOAD_XSTATS_CPU_HIT: 6908c2ecf20Sopenharmony_ci return mlxsw_sp_port_get_sw_stats64(dev, sp); 6918c2ecf20Sopenharmony_ci } 6928c2ecf20Sopenharmony_ci 6938c2ecf20Sopenharmony_ci return -EINVAL; 6948c2ecf20Sopenharmony_ci} 6958c2ecf20Sopenharmony_ci 6968c2ecf20Sopenharmony_ciint mlxsw_sp_port_get_stats_raw(struct net_device *dev, int grp, 6978c2ecf20Sopenharmony_ci int prio, char *ppcnt_pl) 6988c2ecf20Sopenharmony_ci{ 6998c2ecf20Sopenharmony_ci struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(dev); 7008c2ecf20Sopenharmony_ci struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; 7018c2ecf20Sopenharmony_ci 7028c2ecf20Sopenharmony_ci mlxsw_reg_ppcnt_pack(ppcnt_pl, mlxsw_sp_port->local_port, grp, prio); 7038c2ecf20Sopenharmony_ci return mlxsw_reg_query(mlxsw_sp->core, MLXSW_REG(ppcnt), ppcnt_pl); 7048c2ecf20Sopenharmony_ci} 7058c2ecf20Sopenharmony_ci 7068c2ecf20Sopenharmony_cistatic int mlxsw_sp_port_get_hw_stats(struct net_device *dev, 7078c2ecf20Sopenharmony_ci struct rtnl_link_stats64 *stats) 7088c2ecf20Sopenharmony_ci{ 7098c2ecf20Sopenharmony_ci char ppcnt_pl[MLXSW_REG_PPCNT_LEN]; 7108c2ecf20Sopenharmony_ci int err; 7118c2ecf20Sopenharmony_ci 7128c2ecf20Sopenharmony_ci err = mlxsw_sp_port_get_stats_raw(dev, MLXSW_REG_PPCNT_IEEE_8023_CNT, 7138c2ecf20Sopenharmony_ci 0, ppcnt_pl); 7148c2ecf20Sopenharmony_ci if (err) 7158c2ecf20Sopenharmony_ci goto out; 7168c2ecf20Sopenharmony_ci 7178c2ecf20Sopenharmony_ci stats->tx_packets = 7188c2ecf20Sopenharmony_ci mlxsw_reg_ppcnt_a_frames_transmitted_ok_get(ppcnt_pl); 7198c2ecf20Sopenharmony_ci stats->rx_packets = 7208c2ecf20Sopenharmony_ci mlxsw_reg_ppcnt_a_frames_received_ok_get(ppcnt_pl); 7218c2ecf20Sopenharmony_ci stats->tx_bytes = 7228c2ecf20Sopenharmony_ci mlxsw_reg_ppcnt_a_octets_transmitted_ok_get(ppcnt_pl); 7238c2ecf20Sopenharmony_ci stats->rx_bytes = 7248c2ecf20Sopenharmony_ci mlxsw_reg_ppcnt_a_octets_received_ok_get(ppcnt_pl); 7258c2ecf20Sopenharmony_ci stats->multicast = 7268c2ecf20Sopenharmony_ci mlxsw_reg_ppcnt_a_multicast_frames_received_ok_get(ppcnt_pl); 7278c2ecf20Sopenharmony_ci 7288c2ecf20Sopenharmony_ci stats->rx_crc_errors = 7298c2ecf20Sopenharmony_ci mlxsw_reg_ppcnt_a_frame_check_sequence_errors_get(ppcnt_pl); 7308c2ecf20Sopenharmony_ci stats->rx_frame_errors = 7318c2ecf20Sopenharmony_ci mlxsw_reg_ppcnt_a_alignment_errors_get(ppcnt_pl); 7328c2ecf20Sopenharmony_ci 7338c2ecf20Sopenharmony_ci stats->rx_length_errors = ( 7348c2ecf20Sopenharmony_ci mlxsw_reg_ppcnt_a_in_range_length_errors_get(ppcnt_pl) + 7358c2ecf20Sopenharmony_ci mlxsw_reg_ppcnt_a_out_of_range_length_field_get(ppcnt_pl) + 7368c2ecf20Sopenharmony_ci mlxsw_reg_ppcnt_a_frame_too_long_errors_get(ppcnt_pl)); 7378c2ecf20Sopenharmony_ci 7388c2ecf20Sopenharmony_ci stats->rx_errors = (stats->rx_crc_errors + 7398c2ecf20Sopenharmony_ci stats->rx_frame_errors + stats->rx_length_errors); 7408c2ecf20Sopenharmony_ci 7418c2ecf20Sopenharmony_ciout: 7428c2ecf20Sopenharmony_ci return err; 7438c2ecf20Sopenharmony_ci} 7448c2ecf20Sopenharmony_ci 7458c2ecf20Sopenharmony_cistatic void 7468c2ecf20Sopenharmony_cimlxsw_sp_port_get_hw_xstats(struct net_device *dev, 7478c2ecf20Sopenharmony_ci struct mlxsw_sp_port_xstats *xstats) 7488c2ecf20Sopenharmony_ci{ 7498c2ecf20Sopenharmony_ci char ppcnt_pl[MLXSW_REG_PPCNT_LEN]; 7508c2ecf20Sopenharmony_ci int err, i; 7518c2ecf20Sopenharmony_ci 7528c2ecf20Sopenharmony_ci err = mlxsw_sp_port_get_stats_raw(dev, MLXSW_REG_PPCNT_EXT_CNT, 0, 7538c2ecf20Sopenharmony_ci ppcnt_pl); 7548c2ecf20Sopenharmony_ci if (!err) 7558c2ecf20Sopenharmony_ci xstats->ecn = mlxsw_reg_ppcnt_ecn_marked_get(ppcnt_pl); 7568c2ecf20Sopenharmony_ci 7578c2ecf20Sopenharmony_ci for (i = 0; i < TC_MAX_QUEUE; i++) { 7588c2ecf20Sopenharmony_ci err = mlxsw_sp_port_get_stats_raw(dev, 7598c2ecf20Sopenharmony_ci MLXSW_REG_PPCNT_TC_CONG_TC, 7608c2ecf20Sopenharmony_ci i, ppcnt_pl); 7618c2ecf20Sopenharmony_ci if (!err) 7628c2ecf20Sopenharmony_ci xstats->wred_drop[i] = 7638c2ecf20Sopenharmony_ci mlxsw_reg_ppcnt_wred_discard_get(ppcnt_pl); 7648c2ecf20Sopenharmony_ci 7658c2ecf20Sopenharmony_ci err = mlxsw_sp_port_get_stats_raw(dev, MLXSW_REG_PPCNT_TC_CNT, 7668c2ecf20Sopenharmony_ci i, ppcnt_pl); 7678c2ecf20Sopenharmony_ci if (err) 7688c2ecf20Sopenharmony_ci continue; 7698c2ecf20Sopenharmony_ci 7708c2ecf20Sopenharmony_ci xstats->backlog[i] = 7718c2ecf20Sopenharmony_ci mlxsw_reg_ppcnt_tc_transmit_queue_get(ppcnt_pl); 7728c2ecf20Sopenharmony_ci xstats->tail_drop[i] = 7738c2ecf20Sopenharmony_ci mlxsw_reg_ppcnt_tc_no_buffer_discard_uc_get(ppcnt_pl); 7748c2ecf20Sopenharmony_ci } 7758c2ecf20Sopenharmony_ci 7768c2ecf20Sopenharmony_ci for (i = 0; i < IEEE_8021QAZ_MAX_TCS; i++) { 7778c2ecf20Sopenharmony_ci err = mlxsw_sp_port_get_stats_raw(dev, MLXSW_REG_PPCNT_PRIO_CNT, 7788c2ecf20Sopenharmony_ci i, ppcnt_pl); 7798c2ecf20Sopenharmony_ci if (err) 7808c2ecf20Sopenharmony_ci continue; 7818c2ecf20Sopenharmony_ci 7828c2ecf20Sopenharmony_ci xstats->tx_packets[i] = mlxsw_reg_ppcnt_tx_frames_get(ppcnt_pl); 7838c2ecf20Sopenharmony_ci xstats->tx_bytes[i] = mlxsw_reg_ppcnt_tx_octets_get(ppcnt_pl); 7848c2ecf20Sopenharmony_ci } 7858c2ecf20Sopenharmony_ci} 7868c2ecf20Sopenharmony_ci 7878c2ecf20Sopenharmony_cistatic void update_stats_cache(struct work_struct *work) 7888c2ecf20Sopenharmony_ci{ 7898c2ecf20Sopenharmony_ci struct mlxsw_sp_port *mlxsw_sp_port = 7908c2ecf20Sopenharmony_ci container_of(work, struct mlxsw_sp_port, 7918c2ecf20Sopenharmony_ci periodic_hw_stats.update_dw.work); 7928c2ecf20Sopenharmony_ci 7938c2ecf20Sopenharmony_ci if (!netif_carrier_ok(mlxsw_sp_port->dev)) 7948c2ecf20Sopenharmony_ci /* Note: mlxsw_sp_port_down_wipe_counters() clears the cache as 7958c2ecf20Sopenharmony_ci * necessary when port goes down. 7968c2ecf20Sopenharmony_ci */ 7978c2ecf20Sopenharmony_ci goto out; 7988c2ecf20Sopenharmony_ci 7998c2ecf20Sopenharmony_ci mlxsw_sp_port_get_hw_stats(mlxsw_sp_port->dev, 8008c2ecf20Sopenharmony_ci &mlxsw_sp_port->periodic_hw_stats.stats); 8018c2ecf20Sopenharmony_ci mlxsw_sp_port_get_hw_xstats(mlxsw_sp_port->dev, 8028c2ecf20Sopenharmony_ci &mlxsw_sp_port->periodic_hw_stats.xstats); 8038c2ecf20Sopenharmony_ci 8048c2ecf20Sopenharmony_ciout: 8058c2ecf20Sopenharmony_ci mlxsw_core_schedule_dw(&mlxsw_sp_port->periodic_hw_stats.update_dw, 8068c2ecf20Sopenharmony_ci MLXSW_HW_STATS_UPDATE_TIME); 8078c2ecf20Sopenharmony_ci} 8088c2ecf20Sopenharmony_ci 8098c2ecf20Sopenharmony_ci/* Return the stats from a cache that is updated periodically, 8108c2ecf20Sopenharmony_ci * as this function might get called in an atomic context. 8118c2ecf20Sopenharmony_ci */ 8128c2ecf20Sopenharmony_cistatic void 8138c2ecf20Sopenharmony_cimlxsw_sp_port_get_stats64(struct net_device *dev, 8148c2ecf20Sopenharmony_ci struct rtnl_link_stats64 *stats) 8158c2ecf20Sopenharmony_ci{ 8168c2ecf20Sopenharmony_ci struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(dev); 8178c2ecf20Sopenharmony_ci 8188c2ecf20Sopenharmony_ci memcpy(stats, &mlxsw_sp_port->periodic_hw_stats.stats, sizeof(*stats)); 8198c2ecf20Sopenharmony_ci} 8208c2ecf20Sopenharmony_ci 8218c2ecf20Sopenharmony_cistatic int __mlxsw_sp_port_vlan_set(struct mlxsw_sp_port *mlxsw_sp_port, 8228c2ecf20Sopenharmony_ci u16 vid_begin, u16 vid_end, 8238c2ecf20Sopenharmony_ci bool is_member, bool untagged) 8248c2ecf20Sopenharmony_ci{ 8258c2ecf20Sopenharmony_ci struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; 8268c2ecf20Sopenharmony_ci char *spvm_pl; 8278c2ecf20Sopenharmony_ci int err; 8288c2ecf20Sopenharmony_ci 8298c2ecf20Sopenharmony_ci spvm_pl = kmalloc(MLXSW_REG_SPVM_LEN, GFP_KERNEL); 8308c2ecf20Sopenharmony_ci if (!spvm_pl) 8318c2ecf20Sopenharmony_ci return -ENOMEM; 8328c2ecf20Sopenharmony_ci 8338c2ecf20Sopenharmony_ci mlxsw_reg_spvm_pack(spvm_pl, mlxsw_sp_port->local_port, vid_begin, 8348c2ecf20Sopenharmony_ci vid_end, is_member, untagged); 8358c2ecf20Sopenharmony_ci err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(spvm), spvm_pl); 8368c2ecf20Sopenharmony_ci kfree(spvm_pl); 8378c2ecf20Sopenharmony_ci return err; 8388c2ecf20Sopenharmony_ci} 8398c2ecf20Sopenharmony_ci 8408c2ecf20Sopenharmony_ciint mlxsw_sp_port_vlan_set(struct mlxsw_sp_port *mlxsw_sp_port, u16 vid_begin, 8418c2ecf20Sopenharmony_ci u16 vid_end, bool is_member, bool untagged) 8428c2ecf20Sopenharmony_ci{ 8438c2ecf20Sopenharmony_ci u16 vid, vid_e; 8448c2ecf20Sopenharmony_ci int err; 8458c2ecf20Sopenharmony_ci 8468c2ecf20Sopenharmony_ci for (vid = vid_begin; vid <= vid_end; 8478c2ecf20Sopenharmony_ci vid += MLXSW_REG_SPVM_REC_MAX_COUNT) { 8488c2ecf20Sopenharmony_ci vid_e = min((u16) (vid + MLXSW_REG_SPVM_REC_MAX_COUNT - 1), 8498c2ecf20Sopenharmony_ci vid_end); 8508c2ecf20Sopenharmony_ci 8518c2ecf20Sopenharmony_ci err = __mlxsw_sp_port_vlan_set(mlxsw_sp_port, vid, vid_e, 8528c2ecf20Sopenharmony_ci is_member, untagged); 8538c2ecf20Sopenharmony_ci if (err) 8548c2ecf20Sopenharmony_ci return err; 8558c2ecf20Sopenharmony_ci } 8568c2ecf20Sopenharmony_ci 8578c2ecf20Sopenharmony_ci return 0; 8588c2ecf20Sopenharmony_ci} 8598c2ecf20Sopenharmony_ci 8608c2ecf20Sopenharmony_cistatic void mlxsw_sp_port_vlan_flush(struct mlxsw_sp_port *mlxsw_sp_port, 8618c2ecf20Sopenharmony_ci bool flush_default) 8628c2ecf20Sopenharmony_ci{ 8638c2ecf20Sopenharmony_ci struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan, *tmp; 8648c2ecf20Sopenharmony_ci 8658c2ecf20Sopenharmony_ci list_for_each_entry_safe(mlxsw_sp_port_vlan, tmp, 8668c2ecf20Sopenharmony_ci &mlxsw_sp_port->vlans_list, list) { 8678c2ecf20Sopenharmony_ci if (!flush_default && 8688c2ecf20Sopenharmony_ci mlxsw_sp_port_vlan->vid == MLXSW_SP_DEFAULT_VID) 8698c2ecf20Sopenharmony_ci continue; 8708c2ecf20Sopenharmony_ci mlxsw_sp_port_vlan_destroy(mlxsw_sp_port_vlan); 8718c2ecf20Sopenharmony_ci } 8728c2ecf20Sopenharmony_ci} 8738c2ecf20Sopenharmony_ci 8748c2ecf20Sopenharmony_cistatic void 8758c2ecf20Sopenharmony_cimlxsw_sp_port_vlan_cleanup(struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan) 8768c2ecf20Sopenharmony_ci{ 8778c2ecf20Sopenharmony_ci if (mlxsw_sp_port_vlan->bridge_port) 8788c2ecf20Sopenharmony_ci mlxsw_sp_port_vlan_bridge_leave(mlxsw_sp_port_vlan); 8798c2ecf20Sopenharmony_ci else if (mlxsw_sp_port_vlan->fid) 8808c2ecf20Sopenharmony_ci mlxsw_sp_port_vlan_router_leave(mlxsw_sp_port_vlan); 8818c2ecf20Sopenharmony_ci} 8828c2ecf20Sopenharmony_ci 8838c2ecf20Sopenharmony_cistruct mlxsw_sp_port_vlan * 8848c2ecf20Sopenharmony_cimlxsw_sp_port_vlan_create(struct mlxsw_sp_port *mlxsw_sp_port, u16 vid) 8858c2ecf20Sopenharmony_ci{ 8868c2ecf20Sopenharmony_ci struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan; 8878c2ecf20Sopenharmony_ci bool untagged = vid == MLXSW_SP_DEFAULT_VID; 8888c2ecf20Sopenharmony_ci int err; 8898c2ecf20Sopenharmony_ci 8908c2ecf20Sopenharmony_ci mlxsw_sp_port_vlan = mlxsw_sp_port_vlan_find_by_vid(mlxsw_sp_port, vid); 8918c2ecf20Sopenharmony_ci if (mlxsw_sp_port_vlan) 8928c2ecf20Sopenharmony_ci return ERR_PTR(-EEXIST); 8938c2ecf20Sopenharmony_ci 8948c2ecf20Sopenharmony_ci err = mlxsw_sp_port_vlan_set(mlxsw_sp_port, vid, vid, true, untagged); 8958c2ecf20Sopenharmony_ci if (err) 8968c2ecf20Sopenharmony_ci return ERR_PTR(err); 8978c2ecf20Sopenharmony_ci 8988c2ecf20Sopenharmony_ci mlxsw_sp_port_vlan = kzalloc(sizeof(*mlxsw_sp_port_vlan), GFP_KERNEL); 8998c2ecf20Sopenharmony_ci if (!mlxsw_sp_port_vlan) { 9008c2ecf20Sopenharmony_ci err = -ENOMEM; 9018c2ecf20Sopenharmony_ci goto err_port_vlan_alloc; 9028c2ecf20Sopenharmony_ci } 9038c2ecf20Sopenharmony_ci 9048c2ecf20Sopenharmony_ci mlxsw_sp_port_vlan->mlxsw_sp_port = mlxsw_sp_port; 9058c2ecf20Sopenharmony_ci mlxsw_sp_port_vlan->vid = vid; 9068c2ecf20Sopenharmony_ci list_add(&mlxsw_sp_port_vlan->list, &mlxsw_sp_port->vlans_list); 9078c2ecf20Sopenharmony_ci 9088c2ecf20Sopenharmony_ci return mlxsw_sp_port_vlan; 9098c2ecf20Sopenharmony_ci 9108c2ecf20Sopenharmony_cierr_port_vlan_alloc: 9118c2ecf20Sopenharmony_ci mlxsw_sp_port_vlan_set(mlxsw_sp_port, vid, vid, false, false); 9128c2ecf20Sopenharmony_ci return ERR_PTR(err); 9138c2ecf20Sopenharmony_ci} 9148c2ecf20Sopenharmony_ci 9158c2ecf20Sopenharmony_civoid mlxsw_sp_port_vlan_destroy(struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan) 9168c2ecf20Sopenharmony_ci{ 9178c2ecf20Sopenharmony_ci struct mlxsw_sp_port *mlxsw_sp_port = mlxsw_sp_port_vlan->mlxsw_sp_port; 9188c2ecf20Sopenharmony_ci u16 vid = mlxsw_sp_port_vlan->vid; 9198c2ecf20Sopenharmony_ci 9208c2ecf20Sopenharmony_ci mlxsw_sp_port_vlan_cleanup(mlxsw_sp_port_vlan); 9218c2ecf20Sopenharmony_ci list_del(&mlxsw_sp_port_vlan->list); 9228c2ecf20Sopenharmony_ci kfree(mlxsw_sp_port_vlan); 9238c2ecf20Sopenharmony_ci mlxsw_sp_port_vlan_set(mlxsw_sp_port, vid, vid, false, false); 9248c2ecf20Sopenharmony_ci} 9258c2ecf20Sopenharmony_ci 9268c2ecf20Sopenharmony_cistatic int mlxsw_sp_port_add_vid(struct net_device *dev, 9278c2ecf20Sopenharmony_ci __be16 __always_unused proto, u16 vid) 9288c2ecf20Sopenharmony_ci{ 9298c2ecf20Sopenharmony_ci struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(dev); 9308c2ecf20Sopenharmony_ci 9318c2ecf20Sopenharmony_ci /* VLAN 0 is added to HW filter when device goes up, but it is 9328c2ecf20Sopenharmony_ci * reserved in our case, so simply return. 9338c2ecf20Sopenharmony_ci */ 9348c2ecf20Sopenharmony_ci if (!vid) 9358c2ecf20Sopenharmony_ci return 0; 9368c2ecf20Sopenharmony_ci 9378c2ecf20Sopenharmony_ci return PTR_ERR_OR_ZERO(mlxsw_sp_port_vlan_create(mlxsw_sp_port, vid)); 9388c2ecf20Sopenharmony_ci} 9398c2ecf20Sopenharmony_ci 9408c2ecf20Sopenharmony_cistatic int mlxsw_sp_port_kill_vid(struct net_device *dev, 9418c2ecf20Sopenharmony_ci __be16 __always_unused proto, u16 vid) 9428c2ecf20Sopenharmony_ci{ 9438c2ecf20Sopenharmony_ci struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(dev); 9448c2ecf20Sopenharmony_ci struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan; 9458c2ecf20Sopenharmony_ci 9468c2ecf20Sopenharmony_ci /* VLAN 0 is removed from HW filter when device goes down, but 9478c2ecf20Sopenharmony_ci * it is reserved in our case, so simply return. 9488c2ecf20Sopenharmony_ci */ 9498c2ecf20Sopenharmony_ci if (!vid) 9508c2ecf20Sopenharmony_ci return 0; 9518c2ecf20Sopenharmony_ci 9528c2ecf20Sopenharmony_ci mlxsw_sp_port_vlan = mlxsw_sp_port_vlan_find_by_vid(mlxsw_sp_port, vid); 9538c2ecf20Sopenharmony_ci if (!mlxsw_sp_port_vlan) 9548c2ecf20Sopenharmony_ci return 0; 9558c2ecf20Sopenharmony_ci mlxsw_sp_port_vlan_destroy(mlxsw_sp_port_vlan); 9568c2ecf20Sopenharmony_ci 9578c2ecf20Sopenharmony_ci return 0; 9588c2ecf20Sopenharmony_ci} 9598c2ecf20Sopenharmony_ci 9608c2ecf20Sopenharmony_cistatic int mlxsw_sp_setup_tc_block(struct mlxsw_sp_port *mlxsw_sp_port, 9618c2ecf20Sopenharmony_ci struct flow_block_offload *f) 9628c2ecf20Sopenharmony_ci{ 9638c2ecf20Sopenharmony_ci switch (f->binder_type) { 9648c2ecf20Sopenharmony_ci case FLOW_BLOCK_BINDER_TYPE_CLSACT_INGRESS: 9658c2ecf20Sopenharmony_ci return mlxsw_sp_setup_tc_block_clsact(mlxsw_sp_port, f, true); 9668c2ecf20Sopenharmony_ci case FLOW_BLOCK_BINDER_TYPE_CLSACT_EGRESS: 9678c2ecf20Sopenharmony_ci return mlxsw_sp_setup_tc_block_clsact(mlxsw_sp_port, f, false); 9688c2ecf20Sopenharmony_ci case FLOW_BLOCK_BINDER_TYPE_RED_EARLY_DROP: 9698c2ecf20Sopenharmony_ci return mlxsw_sp_setup_tc_block_qevent_early_drop(mlxsw_sp_port, f); 9708c2ecf20Sopenharmony_ci default: 9718c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 9728c2ecf20Sopenharmony_ci } 9738c2ecf20Sopenharmony_ci} 9748c2ecf20Sopenharmony_ci 9758c2ecf20Sopenharmony_cistatic int mlxsw_sp_setup_tc(struct net_device *dev, enum tc_setup_type type, 9768c2ecf20Sopenharmony_ci void *type_data) 9778c2ecf20Sopenharmony_ci{ 9788c2ecf20Sopenharmony_ci struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(dev); 9798c2ecf20Sopenharmony_ci 9808c2ecf20Sopenharmony_ci switch (type) { 9818c2ecf20Sopenharmony_ci case TC_SETUP_BLOCK: 9828c2ecf20Sopenharmony_ci return mlxsw_sp_setup_tc_block(mlxsw_sp_port, type_data); 9838c2ecf20Sopenharmony_ci case TC_SETUP_QDISC_RED: 9848c2ecf20Sopenharmony_ci return mlxsw_sp_setup_tc_red(mlxsw_sp_port, type_data); 9858c2ecf20Sopenharmony_ci case TC_SETUP_QDISC_PRIO: 9868c2ecf20Sopenharmony_ci return mlxsw_sp_setup_tc_prio(mlxsw_sp_port, type_data); 9878c2ecf20Sopenharmony_ci case TC_SETUP_QDISC_ETS: 9888c2ecf20Sopenharmony_ci return mlxsw_sp_setup_tc_ets(mlxsw_sp_port, type_data); 9898c2ecf20Sopenharmony_ci case TC_SETUP_QDISC_TBF: 9908c2ecf20Sopenharmony_ci return mlxsw_sp_setup_tc_tbf(mlxsw_sp_port, type_data); 9918c2ecf20Sopenharmony_ci case TC_SETUP_QDISC_FIFO: 9928c2ecf20Sopenharmony_ci return mlxsw_sp_setup_tc_fifo(mlxsw_sp_port, type_data); 9938c2ecf20Sopenharmony_ci default: 9948c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 9958c2ecf20Sopenharmony_ci } 9968c2ecf20Sopenharmony_ci} 9978c2ecf20Sopenharmony_ci 9988c2ecf20Sopenharmony_cistatic int mlxsw_sp_feature_hw_tc(struct net_device *dev, bool enable) 9998c2ecf20Sopenharmony_ci{ 10008c2ecf20Sopenharmony_ci struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(dev); 10018c2ecf20Sopenharmony_ci 10028c2ecf20Sopenharmony_ci if (!enable) { 10038c2ecf20Sopenharmony_ci if (mlxsw_sp_flow_block_rule_count(mlxsw_sp_port->ing_flow_block) || 10048c2ecf20Sopenharmony_ci mlxsw_sp_flow_block_rule_count(mlxsw_sp_port->eg_flow_block)) { 10058c2ecf20Sopenharmony_ci netdev_err(dev, "Active offloaded tc filters, can't turn hw_tc_offload off\n"); 10068c2ecf20Sopenharmony_ci return -EINVAL; 10078c2ecf20Sopenharmony_ci } 10088c2ecf20Sopenharmony_ci mlxsw_sp_flow_block_disable_inc(mlxsw_sp_port->ing_flow_block); 10098c2ecf20Sopenharmony_ci mlxsw_sp_flow_block_disable_inc(mlxsw_sp_port->eg_flow_block); 10108c2ecf20Sopenharmony_ci } else { 10118c2ecf20Sopenharmony_ci mlxsw_sp_flow_block_disable_dec(mlxsw_sp_port->ing_flow_block); 10128c2ecf20Sopenharmony_ci mlxsw_sp_flow_block_disable_dec(mlxsw_sp_port->eg_flow_block); 10138c2ecf20Sopenharmony_ci } 10148c2ecf20Sopenharmony_ci return 0; 10158c2ecf20Sopenharmony_ci} 10168c2ecf20Sopenharmony_ci 10178c2ecf20Sopenharmony_cistatic int mlxsw_sp_feature_loopback(struct net_device *dev, bool enable) 10188c2ecf20Sopenharmony_ci{ 10198c2ecf20Sopenharmony_ci struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(dev); 10208c2ecf20Sopenharmony_ci char pplr_pl[MLXSW_REG_PPLR_LEN]; 10218c2ecf20Sopenharmony_ci int err; 10228c2ecf20Sopenharmony_ci 10238c2ecf20Sopenharmony_ci if (netif_running(dev)) 10248c2ecf20Sopenharmony_ci mlxsw_sp_port_admin_status_set(mlxsw_sp_port, false); 10258c2ecf20Sopenharmony_ci 10268c2ecf20Sopenharmony_ci mlxsw_reg_pplr_pack(pplr_pl, mlxsw_sp_port->local_port, enable); 10278c2ecf20Sopenharmony_ci err = mlxsw_reg_write(mlxsw_sp_port->mlxsw_sp->core, MLXSW_REG(pplr), 10288c2ecf20Sopenharmony_ci pplr_pl); 10298c2ecf20Sopenharmony_ci 10308c2ecf20Sopenharmony_ci if (netif_running(dev)) 10318c2ecf20Sopenharmony_ci mlxsw_sp_port_admin_status_set(mlxsw_sp_port, true); 10328c2ecf20Sopenharmony_ci 10338c2ecf20Sopenharmony_ci return err; 10348c2ecf20Sopenharmony_ci} 10358c2ecf20Sopenharmony_ci 10368c2ecf20Sopenharmony_citypedef int (*mlxsw_sp_feature_handler)(struct net_device *dev, bool enable); 10378c2ecf20Sopenharmony_ci 10388c2ecf20Sopenharmony_cistatic int mlxsw_sp_handle_feature(struct net_device *dev, 10398c2ecf20Sopenharmony_ci netdev_features_t wanted_features, 10408c2ecf20Sopenharmony_ci netdev_features_t feature, 10418c2ecf20Sopenharmony_ci mlxsw_sp_feature_handler feature_handler) 10428c2ecf20Sopenharmony_ci{ 10438c2ecf20Sopenharmony_ci netdev_features_t changes = wanted_features ^ dev->features; 10448c2ecf20Sopenharmony_ci bool enable = !!(wanted_features & feature); 10458c2ecf20Sopenharmony_ci int err; 10468c2ecf20Sopenharmony_ci 10478c2ecf20Sopenharmony_ci if (!(changes & feature)) 10488c2ecf20Sopenharmony_ci return 0; 10498c2ecf20Sopenharmony_ci 10508c2ecf20Sopenharmony_ci err = feature_handler(dev, enable); 10518c2ecf20Sopenharmony_ci if (err) { 10528c2ecf20Sopenharmony_ci netdev_err(dev, "%s feature %pNF failed, err %d\n", 10538c2ecf20Sopenharmony_ci enable ? "Enable" : "Disable", &feature, err); 10548c2ecf20Sopenharmony_ci return err; 10558c2ecf20Sopenharmony_ci } 10568c2ecf20Sopenharmony_ci 10578c2ecf20Sopenharmony_ci if (enable) 10588c2ecf20Sopenharmony_ci dev->features |= feature; 10598c2ecf20Sopenharmony_ci else 10608c2ecf20Sopenharmony_ci dev->features &= ~feature; 10618c2ecf20Sopenharmony_ci 10628c2ecf20Sopenharmony_ci return 0; 10638c2ecf20Sopenharmony_ci} 10648c2ecf20Sopenharmony_cistatic int mlxsw_sp_set_features(struct net_device *dev, 10658c2ecf20Sopenharmony_ci netdev_features_t features) 10668c2ecf20Sopenharmony_ci{ 10678c2ecf20Sopenharmony_ci netdev_features_t oper_features = dev->features; 10688c2ecf20Sopenharmony_ci int err = 0; 10698c2ecf20Sopenharmony_ci 10708c2ecf20Sopenharmony_ci err |= mlxsw_sp_handle_feature(dev, features, NETIF_F_HW_TC, 10718c2ecf20Sopenharmony_ci mlxsw_sp_feature_hw_tc); 10728c2ecf20Sopenharmony_ci err |= mlxsw_sp_handle_feature(dev, features, NETIF_F_LOOPBACK, 10738c2ecf20Sopenharmony_ci mlxsw_sp_feature_loopback); 10748c2ecf20Sopenharmony_ci 10758c2ecf20Sopenharmony_ci if (err) { 10768c2ecf20Sopenharmony_ci dev->features = oper_features; 10778c2ecf20Sopenharmony_ci return -EINVAL; 10788c2ecf20Sopenharmony_ci } 10798c2ecf20Sopenharmony_ci 10808c2ecf20Sopenharmony_ci return 0; 10818c2ecf20Sopenharmony_ci} 10828c2ecf20Sopenharmony_ci 10838c2ecf20Sopenharmony_cistatic struct devlink_port * 10848c2ecf20Sopenharmony_cimlxsw_sp_port_get_devlink_port(struct net_device *dev) 10858c2ecf20Sopenharmony_ci{ 10868c2ecf20Sopenharmony_ci struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(dev); 10878c2ecf20Sopenharmony_ci struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; 10888c2ecf20Sopenharmony_ci 10898c2ecf20Sopenharmony_ci return mlxsw_core_port_devlink_port_get(mlxsw_sp->core, 10908c2ecf20Sopenharmony_ci mlxsw_sp_port->local_port); 10918c2ecf20Sopenharmony_ci} 10928c2ecf20Sopenharmony_ci 10938c2ecf20Sopenharmony_cistatic int mlxsw_sp_port_hwtstamp_set(struct mlxsw_sp_port *mlxsw_sp_port, 10948c2ecf20Sopenharmony_ci struct ifreq *ifr) 10958c2ecf20Sopenharmony_ci{ 10968c2ecf20Sopenharmony_ci struct hwtstamp_config config; 10978c2ecf20Sopenharmony_ci int err; 10988c2ecf20Sopenharmony_ci 10998c2ecf20Sopenharmony_ci if (copy_from_user(&config, ifr->ifr_data, sizeof(config))) 11008c2ecf20Sopenharmony_ci return -EFAULT; 11018c2ecf20Sopenharmony_ci 11028c2ecf20Sopenharmony_ci err = mlxsw_sp_port->mlxsw_sp->ptp_ops->hwtstamp_set(mlxsw_sp_port, 11038c2ecf20Sopenharmony_ci &config); 11048c2ecf20Sopenharmony_ci if (err) 11058c2ecf20Sopenharmony_ci return err; 11068c2ecf20Sopenharmony_ci 11078c2ecf20Sopenharmony_ci if (copy_to_user(ifr->ifr_data, &config, sizeof(config))) 11088c2ecf20Sopenharmony_ci return -EFAULT; 11098c2ecf20Sopenharmony_ci 11108c2ecf20Sopenharmony_ci return 0; 11118c2ecf20Sopenharmony_ci} 11128c2ecf20Sopenharmony_ci 11138c2ecf20Sopenharmony_cistatic int mlxsw_sp_port_hwtstamp_get(struct mlxsw_sp_port *mlxsw_sp_port, 11148c2ecf20Sopenharmony_ci struct ifreq *ifr) 11158c2ecf20Sopenharmony_ci{ 11168c2ecf20Sopenharmony_ci struct hwtstamp_config config; 11178c2ecf20Sopenharmony_ci int err; 11188c2ecf20Sopenharmony_ci 11198c2ecf20Sopenharmony_ci err = mlxsw_sp_port->mlxsw_sp->ptp_ops->hwtstamp_get(mlxsw_sp_port, 11208c2ecf20Sopenharmony_ci &config); 11218c2ecf20Sopenharmony_ci if (err) 11228c2ecf20Sopenharmony_ci return err; 11238c2ecf20Sopenharmony_ci 11248c2ecf20Sopenharmony_ci if (copy_to_user(ifr->ifr_data, &config, sizeof(config))) 11258c2ecf20Sopenharmony_ci return -EFAULT; 11268c2ecf20Sopenharmony_ci 11278c2ecf20Sopenharmony_ci return 0; 11288c2ecf20Sopenharmony_ci} 11298c2ecf20Sopenharmony_ci 11308c2ecf20Sopenharmony_cistatic inline void mlxsw_sp_port_ptp_clear(struct mlxsw_sp_port *mlxsw_sp_port) 11318c2ecf20Sopenharmony_ci{ 11328c2ecf20Sopenharmony_ci struct hwtstamp_config config = {0}; 11338c2ecf20Sopenharmony_ci 11348c2ecf20Sopenharmony_ci mlxsw_sp_port->mlxsw_sp->ptp_ops->hwtstamp_set(mlxsw_sp_port, &config); 11358c2ecf20Sopenharmony_ci} 11368c2ecf20Sopenharmony_ci 11378c2ecf20Sopenharmony_cistatic int 11388c2ecf20Sopenharmony_cimlxsw_sp_port_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) 11398c2ecf20Sopenharmony_ci{ 11408c2ecf20Sopenharmony_ci struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(dev); 11418c2ecf20Sopenharmony_ci 11428c2ecf20Sopenharmony_ci switch (cmd) { 11438c2ecf20Sopenharmony_ci case SIOCSHWTSTAMP: 11448c2ecf20Sopenharmony_ci return mlxsw_sp_port_hwtstamp_set(mlxsw_sp_port, ifr); 11458c2ecf20Sopenharmony_ci case SIOCGHWTSTAMP: 11468c2ecf20Sopenharmony_ci return mlxsw_sp_port_hwtstamp_get(mlxsw_sp_port, ifr); 11478c2ecf20Sopenharmony_ci default: 11488c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 11498c2ecf20Sopenharmony_ci } 11508c2ecf20Sopenharmony_ci} 11518c2ecf20Sopenharmony_ci 11528c2ecf20Sopenharmony_cistatic const struct net_device_ops mlxsw_sp_port_netdev_ops = { 11538c2ecf20Sopenharmony_ci .ndo_open = mlxsw_sp_port_open, 11548c2ecf20Sopenharmony_ci .ndo_stop = mlxsw_sp_port_stop, 11558c2ecf20Sopenharmony_ci .ndo_start_xmit = mlxsw_sp_port_xmit, 11568c2ecf20Sopenharmony_ci .ndo_setup_tc = mlxsw_sp_setup_tc, 11578c2ecf20Sopenharmony_ci .ndo_set_rx_mode = mlxsw_sp_set_rx_mode, 11588c2ecf20Sopenharmony_ci .ndo_set_mac_address = mlxsw_sp_port_set_mac_address, 11598c2ecf20Sopenharmony_ci .ndo_change_mtu = mlxsw_sp_port_change_mtu, 11608c2ecf20Sopenharmony_ci .ndo_get_stats64 = mlxsw_sp_port_get_stats64, 11618c2ecf20Sopenharmony_ci .ndo_has_offload_stats = mlxsw_sp_port_has_offload_stats, 11628c2ecf20Sopenharmony_ci .ndo_get_offload_stats = mlxsw_sp_port_get_offload_stats, 11638c2ecf20Sopenharmony_ci .ndo_vlan_rx_add_vid = mlxsw_sp_port_add_vid, 11648c2ecf20Sopenharmony_ci .ndo_vlan_rx_kill_vid = mlxsw_sp_port_kill_vid, 11658c2ecf20Sopenharmony_ci .ndo_set_features = mlxsw_sp_set_features, 11668c2ecf20Sopenharmony_ci .ndo_get_devlink_port = mlxsw_sp_port_get_devlink_port, 11678c2ecf20Sopenharmony_ci .ndo_do_ioctl = mlxsw_sp_port_ioctl, 11688c2ecf20Sopenharmony_ci}; 11698c2ecf20Sopenharmony_ci 11708c2ecf20Sopenharmony_cistatic int 11718c2ecf20Sopenharmony_cimlxsw_sp_port_speed_by_width_set(struct mlxsw_sp_port *mlxsw_sp_port) 11728c2ecf20Sopenharmony_ci{ 11738c2ecf20Sopenharmony_ci struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; 11748c2ecf20Sopenharmony_ci u32 eth_proto_cap, eth_proto_admin, eth_proto_oper; 11758c2ecf20Sopenharmony_ci const struct mlxsw_sp_port_type_speed_ops *ops; 11768c2ecf20Sopenharmony_ci char ptys_pl[MLXSW_REG_PTYS_LEN]; 11778c2ecf20Sopenharmony_ci u32 eth_proto_cap_masked; 11788c2ecf20Sopenharmony_ci int err; 11798c2ecf20Sopenharmony_ci 11808c2ecf20Sopenharmony_ci ops = mlxsw_sp->port_type_speed_ops; 11818c2ecf20Sopenharmony_ci 11828c2ecf20Sopenharmony_ci /* Set advertised speeds to speeds supported by both the driver 11838c2ecf20Sopenharmony_ci * and the device. 11848c2ecf20Sopenharmony_ci */ 11858c2ecf20Sopenharmony_ci ops->reg_ptys_eth_pack(mlxsw_sp, ptys_pl, mlxsw_sp_port->local_port, 11868c2ecf20Sopenharmony_ci 0, false); 11878c2ecf20Sopenharmony_ci err = mlxsw_reg_query(mlxsw_sp->core, MLXSW_REG(ptys), ptys_pl); 11888c2ecf20Sopenharmony_ci if (err) 11898c2ecf20Sopenharmony_ci return err; 11908c2ecf20Sopenharmony_ci 11918c2ecf20Sopenharmony_ci ops->reg_ptys_eth_unpack(mlxsw_sp, ptys_pl, ð_proto_cap, 11928c2ecf20Sopenharmony_ci ð_proto_admin, ð_proto_oper); 11938c2ecf20Sopenharmony_ci eth_proto_cap_masked = ops->ptys_proto_cap_masked_get(eth_proto_cap); 11948c2ecf20Sopenharmony_ci ops->reg_ptys_eth_pack(mlxsw_sp, ptys_pl, mlxsw_sp_port->local_port, 11958c2ecf20Sopenharmony_ci eth_proto_cap_masked, 11968c2ecf20Sopenharmony_ci mlxsw_sp_port->link.autoneg); 11978c2ecf20Sopenharmony_ci return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(ptys), ptys_pl); 11988c2ecf20Sopenharmony_ci} 11998c2ecf20Sopenharmony_ci 12008c2ecf20Sopenharmony_ciint mlxsw_sp_port_speed_get(struct mlxsw_sp_port *mlxsw_sp_port, u32 *speed) 12018c2ecf20Sopenharmony_ci{ 12028c2ecf20Sopenharmony_ci const struct mlxsw_sp_port_type_speed_ops *port_type_speed_ops; 12038c2ecf20Sopenharmony_ci struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; 12048c2ecf20Sopenharmony_ci char ptys_pl[MLXSW_REG_PTYS_LEN]; 12058c2ecf20Sopenharmony_ci u32 eth_proto_oper; 12068c2ecf20Sopenharmony_ci int err; 12078c2ecf20Sopenharmony_ci 12088c2ecf20Sopenharmony_ci port_type_speed_ops = mlxsw_sp->port_type_speed_ops; 12098c2ecf20Sopenharmony_ci port_type_speed_ops->reg_ptys_eth_pack(mlxsw_sp, ptys_pl, 12108c2ecf20Sopenharmony_ci mlxsw_sp_port->local_port, 0, 12118c2ecf20Sopenharmony_ci false); 12128c2ecf20Sopenharmony_ci err = mlxsw_reg_query(mlxsw_sp->core, MLXSW_REG(ptys), ptys_pl); 12138c2ecf20Sopenharmony_ci if (err) 12148c2ecf20Sopenharmony_ci return err; 12158c2ecf20Sopenharmony_ci port_type_speed_ops->reg_ptys_eth_unpack(mlxsw_sp, ptys_pl, NULL, NULL, 12168c2ecf20Sopenharmony_ci ð_proto_oper); 12178c2ecf20Sopenharmony_ci *speed = port_type_speed_ops->from_ptys_speed(mlxsw_sp, eth_proto_oper); 12188c2ecf20Sopenharmony_ci return 0; 12198c2ecf20Sopenharmony_ci} 12208c2ecf20Sopenharmony_ci 12218c2ecf20Sopenharmony_ciint mlxsw_sp_port_ets_set(struct mlxsw_sp_port *mlxsw_sp_port, 12228c2ecf20Sopenharmony_ci enum mlxsw_reg_qeec_hr hr, u8 index, u8 next_index, 12238c2ecf20Sopenharmony_ci bool dwrr, u8 dwrr_weight) 12248c2ecf20Sopenharmony_ci{ 12258c2ecf20Sopenharmony_ci struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; 12268c2ecf20Sopenharmony_ci char qeec_pl[MLXSW_REG_QEEC_LEN]; 12278c2ecf20Sopenharmony_ci 12288c2ecf20Sopenharmony_ci mlxsw_reg_qeec_pack(qeec_pl, mlxsw_sp_port->local_port, hr, index, 12298c2ecf20Sopenharmony_ci next_index); 12308c2ecf20Sopenharmony_ci mlxsw_reg_qeec_de_set(qeec_pl, true); 12318c2ecf20Sopenharmony_ci mlxsw_reg_qeec_dwrr_set(qeec_pl, dwrr); 12328c2ecf20Sopenharmony_ci mlxsw_reg_qeec_dwrr_weight_set(qeec_pl, dwrr_weight); 12338c2ecf20Sopenharmony_ci return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(qeec), qeec_pl); 12348c2ecf20Sopenharmony_ci} 12358c2ecf20Sopenharmony_ci 12368c2ecf20Sopenharmony_ciint mlxsw_sp_port_ets_maxrate_set(struct mlxsw_sp_port *mlxsw_sp_port, 12378c2ecf20Sopenharmony_ci enum mlxsw_reg_qeec_hr hr, u8 index, 12388c2ecf20Sopenharmony_ci u8 next_index, u32 maxrate, u8 burst_size) 12398c2ecf20Sopenharmony_ci{ 12408c2ecf20Sopenharmony_ci struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; 12418c2ecf20Sopenharmony_ci char qeec_pl[MLXSW_REG_QEEC_LEN]; 12428c2ecf20Sopenharmony_ci 12438c2ecf20Sopenharmony_ci mlxsw_reg_qeec_pack(qeec_pl, mlxsw_sp_port->local_port, hr, index, 12448c2ecf20Sopenharmony_ci next_index); 12458c2ecf20Sopenharmony_ci mlxsw_reg_qeec_mase_set(qeec_pl, true); 12468c2ecf20Sopenharmony_ci mlxsw_reg_qeec_max_shaper_rate_set(qeec_pl, maxrate); 12478c2ecf20Sopenharmony_ci mlxsw_reg_qeec_max_shaper_bs_set(qeec_pl, burst_size); 12488c2ecf20Sopenharmony_ci return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(qeec), qeec_pl); 12498c2ecf20Sopenharmony_ci} 12508c2ecf20Sopenharmony_ci 12518c2ecf20Sopenharmony_cistatic int mlxsw_sp_port_min_bw_set(struct mlxsw_sp_port *mlxsw_sp_port, 12528c2ecf20Sopenharmony_ci enum mlxsw_reg_qeec_hr hr, u8 index, 12538c2ecf20Sopenharmony_ci u8 next_index, u32 minrate) 12548c2ecf20Sopenharmony_ci{ 12558c2ecf20Sopenharmony_ci struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; 12568c2ecf20Sopenharmony_ci char qeec_pl[MLXSW_REG_QEEC_LEN]; 12578c2ecf20Sopenharmony_ci 12588c2ecf20Sopenharmony_ci mlxsw_reg_qeec_pack(qeec_pl, mlxsw_sp_port->local_port, hr, index, 12598c2ecf20Sopenharmony_ci next_index); 12608c2ecf20Sopenharmony_ci mlxsw_reg_qeec_mise_set(qeec_pl, true); 12618c2ecf20Sopenharmony_ci mlxsw_reg_qeec_min_shaper_rate_set(qeec_pl, minrate); 12628c2ecf20Sopenharmony_ci 12638c2ecf20Sopenharmony_ci return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(qeec), qeec_pl); 12648c2ecf20Sopenharmony_ci} 12658c2ecf20Sopenharmony_ci 12668c2ecf20Sopenharmony_ciint mlxsw_sp_port_prio_tc_set(struct mlxsw_sp_port *mlxsw_sp_port, 12678c2ecf20Sopenharmony_ci u8 switch_prio, u8 tclass) 12688c2ecf20Sopenharmony_ci{ 12698c2ecf20Sopenharmony_ci struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; 12708c2ecf20Sopenharmony_ci char qtct_pl[MLXSW_REG_QTCT_LEN]; 12718c2ecf20Sopenharmony_ci 12728c2ecf20Sopenharmony_ci mlxsw_reg_qtct_pack(qtct_pl, mlxsw_sp_port->local_port, switch_prio, 12738c2ecf20Sopenharmony_ci tclass); 12748c2ecf20Sopenharmony_ci return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(qtct), qtct_pl); 12758c2ecf20Sopenharmony_ci} 12768c2ecf20Sopenharmony_ci 12778c2ecf20Sopenharmony_cistatic int mlxsw_sp_port_ets_init(struct mlxsw_sp_port *mlxsw_sp_port) 12788c2ecf20Sopenharmony_ci{ 12798c2ecf20Sopenharmony_ci int err, i; 12808c2ecf20Sopenharmony_ci 12818c2ecf20Sopenharmony_ci /* Setup the elements hierarcy, so that each TC is linked to 12828c2ecf20Sopenharmony_ci * one subgroup, which are all member in the same group. 12838c2ecf20Sopenharmony_ci */ 12848c2ecf20Sopenharmony_ci err = mlxsw_sp_port_ets_set(mlxsw_sp_port, 12858c2ecf20Sopenharmony_ci MLXSW_REG_QEEC_HR_GROUP, 0, 0, false, 0); 12868c2ecf20Sopenharmony_ci if (err) 12878c2ecf20Sopenharmony_ci return err; 12888c2ecf20Sopenharmony_ci for (i = 0; i < IEEE_8021QAZ_MAX_TCS; i++) { 12898c2ecf20Sopenharmony_ci err = mlxsw_sp_port_ets_set(mlxsw_sp_port, 12908c2ecf20Sopenharmony_ci MLXSW_REG_QEEC_HR_SUBGROUP, i, 12918c2ecf20Sopenharmony_ci 0, false, 0); 12928c2ecf20Sopenharmony_ci if (err) 12938c2ecf20Sopenharmony_ci return err; 12948c2ecf20Sopenharmony_ci } 12958c2ecf20Sopenharmony_ci for (i = 0; i < IEEE_8021QAZ_MAX_TCS; i++) { 12968c2ecf20Sopenharmony_ci err = mlxsw_sp_port_ets_set(mlxsw_sp_port, 12978c2ecf20Sopenharmony_ci MLXSW_REG_QEEC_HR_TC, i, i, 12988c2ecf20Sopenharmony_ci false, 0); 12998c2ecf20Sopenharmony_ci if (err) 13008c2ecf20Sopenharmony_ci return err; 13018c2ecf20Sopenharmony_ci 13028c2ecf20Sopenharmony_ci err = mlxsw_sp_port_ets_set(mlxsw_sp_port, 13038c2ecf20Sopenharmony_ci MLXSW_REG_QEEC_HR_TC, 13048c2ecf20Sopenharmony_ci i + 8, i, 13058c2ecf20Sopenharmony_ci true, 100); 13068c2ecf20Sopenharmony_ci if (err) 13078c2ecf20Sopenharmony_ci return err; 13088c2ecf20Sopenharmony_ci } 13098c2ecf20Sopenharmony_ci 13108c2ecf20Sopenharmony_ci /* Make sure the max shaper is disabled in all hierarchies that support 13118c2ecf20Sopenharmony_ci * it. Note that this disables ptps (PTP shaper), but that is intended 13128c2ecf20Sopenharmony_ci * for the initial configuration. 13138c2ecf20Sopenharmony_ci */ 13148c2ecf20Sopenharmony_ci err = mlxsw_sp_port_ets_maxrate_set(mlxsw_sp_port, 13158c2ecf20Sopenharmony_ci MLXSW_REG_QEEC_HR_PORT, 0, 0, 13168c2ecf20Sopenharmony_ci MLXSW_REG_QEEC_MAS_DIS, 0); 13178c2ecf20Sopenharmony_ci if (err) 13188c2ecf20Sopenharmony_ci return err; 13198c2ecf20Sopenharmony_ci for (i = 0; i < IEEE_8021QAZ_MAX_TCS; i++) { 13208c2ecf20Sopenharmony_ci err = mlxsw_sp_port_ets_maxrate_set(mlxsw_sp_port, 13218c2ecf20Sopenharmony_ci MLXSW_REG_QEEC_HR_SUBGROUP, 13228c2ecf20Sopenharmony_ci i, 0, 13238c2ecf20Sopenharmony_ci MLXSW_REG_QEEC_MAS_DIS, 0); 13248c2ecf20Sopenharmony_ci if (err) 13258c2ecf20Sopenharmony_ci return err; 13268c2ecf20Sopenharmony_ci } 13278c2ecf20Sopenharmony_ci for (i = 0; i < IEEE_8021QAZ_MAX_TCS; i++) { 13288c2ecf20Sopenharmony_ci err = mlxsw_sp_port_ets_maxrate_set(mlxsw_sp_port, 13298c2ecf20Sopenharmony_ci MLXSW_REG_QEEC_HR_TC, 13308c2ecf20Sopenharmony_ci i, i, 13318c2ecf20Sopenharmony_ci MLXSW_REG_QEEC_MAS_DIS, 0); 13328c2ecf20Sopenharmony_ci if (err) 13338c2ecf20Sopenharmony_ci return err; 13348c2ecf20Sopenharmony_ci 13358c2ecf20Sopenharmony_ci err = mlxsw_sp_port_ets_maxrate_set(mlxsw_sp_port, 13368c2ecf20Sopenharmony_ci MLXSW_REG_QEEC_HR_TC, 13378c2ecf20Sopenharmony_ci i + 8, i, 13388c2ecf20Sopenharmony_ci MLXSW_REG_QEEC_MAS_DIS, 0); 13398c2ecf20Sopenharmony_ci if (err) 13408c2ecf20Sopenharmony_ci return err; 13418c2ecf20Sopenharmony_ci } 13428c2ecf20Sopenharmony_ci 13438c2ecf20Sopenharmony_ci /* Configure the min shaper for multicast TCs. */ 13448c2ecf20Sopenharmony_ci for (i = 0; i < IEEE_8021QAZ_MAX_TCS; i++) { 13458c2ecf20Sopenharmony_ci err = mlxsw_sp_port_min_bw_set(mlxsw_sp_port, 13468c2ecf20Sopenharmony_ci MLXSW_REG_QEEC_HR_TC, 13478c2ecf20Sopenharmony_ci i + 8, i, 13488c2ecf20Sopenharmony_ci MLXSW_REG_QEEC_MIS_MIN); 13498c2ecf20Sopenharmony_ci if (err) 13508c2ecf20Sopenharmony_ci return err; 13518c2ecf20Sopenharmony_ci } 13528c2ecf20Sopenharmony_ci 13538c2ecf20Sopenharmony_ci /* Map all priorities to traffic class 0. */ 13548c2ecf20Sopenharmony_ci for (i = 0; i < IEEE_8021QAZ_MAX_TCS; i++) { 13558c2ecf20Sopenharmony_ci err = mlxsw_sp_port_prio_tc_set(mlxsw_sp_port, i, 0); 13568c2ecf20Sopenharmony_ci if (err) 13578c2ecf20Sopenharmony_ci return err; 13588c2ecf20Sopenharmony_ci } 13598c2ecf20Sopenharmony_ci 13608c2ecf20Sopenharmony_ci return 0; 13618c2ecf20Sopenharmony_ci} 13628c2ecf20Sopenharmony_ci 13638c2ecf20Sopenharmony_cistatic int mlxsw_sp_port_tc_mc_mode_set(struct mlxsw_sp_port *mlxsw_sp_port, 13648c2ecf20Sopenharmony_ci bool enable) 13658c2ecf20Sopenharmony_ci{ 13668c2ecf20Sopenharmony_ci struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; 13678c2ecf20Sopenharmony_ci char qtctm_pl[MLXSW_REG_QTCTM_LEN]; 13688c2ecf20Sopenharmony_ci 13698c2ecf20Sopenharmony_ci mlxsw_reg_qtctm_pack(qtctm_pl, mlxsw_sp_port->local_port, enable); 13708c2ecf20Sopenharmony_ci return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(qtctm), qtctm_pl); 13718c2ecf20Sopenharmony_ci} 13728c2ecf20Sopenharmony_ci 13738c2ecf20Sopenharmony_cistatic int mlxsw_sp_port_overheat_init_val_set(struct mlxsw_sp_port *mlxsw_sp_port) 13748c2ecf20Sopenharmony_ci{ 13758c2ecf20Sopenharmony_ci struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; 13768c2ecf20Sopenharmony_ci u8 module = mlxsw_sp_port->mapping.module; 13778c2ecf20Sopenharmony_ci u64 overheat_counter; 13788c2ecf20Sopenharmony_ci int err; 13798c2ecf20Sopenharmony_ci 13808c2ecf20Sopenharmony_ci err = mlxsw_env_module_overheat_counter_get(mlxsw_sp->core, module, 13818c2ecf20Sopenharmony_ci &overheat_counter); 13828c2ecf20Sopenharmony_ci if (err) 13838c2ecf20Sopenharmony_ci return err; 13848c2ecf20Sopenharmony_ci 13858c2ecf20Sopenharmony_ci mlxsw_sp_port->module_overheat_initial_val = overheat_counter; 13868c2ecf20Sopenharmony_ci return 0; 13878c2ecf20Sopenharmony_ci} 13888c2ecf20Sopenharmony_ci 13898c2ecf20Sopenharmony_cistatic int mlxsw_sp_port_create(struct mlxsw_sp *mlxsw_sp, u8 local_port, 13908c2ecf20Sopenharmony_ci u8 split_base_local_port, 13918c2ecf20Sopenharmony_ci struct mlxsw_sp_port_mapping *port_mapping) 13928c2ecf20Sopenharmony_ci{ 13938c2ecf20Sopenharmony_ci struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan; 13948c2ecf20Sopenharmony_ci bool split = !!split_base_local_port; 13958c2ecf20Sopenharmony_ci struct mlxsw_sp_port *mlxsw_sp_port; 13968c2ecf20Sopenharmony_ci u32 lanes = port_mapping->width; 13978c2ecf20Sopenharmony_ci struct net_device *dev; 13988c2ecf20Sopenharmony_ci bool splittable; 13998c2ecf20Sopenharmony_ci int err; 14008c2ecf20Sopenharmony_ci 14018c2ecf20Sopenharmony_ci splittable = lanes > 1 && !split; 14028c2ecf20Sopenharmony_ci err = mlxsw_core_port_init(mlxsw_sp->core, local_port, 14038c2ecf20Sopenharmony_ci port_mapping->module + 1, split, 14048c2ecf20Sopenharmony_ci port_mapping->lane / lanes, 14058c2ecf20Sopenharmony_ci splittable, lanes, 14068c2ecf20Sopenharmony_ci mlxsw_sp->base_mac, 14078c2ecf20Sopenharmony_ci sizeof(mlxsw_sp->base_mac)); 14088c2ecf20Sopenharmony_ci if (err) { 14098c2ecf20Sopenharmony_ci dev_err(mlxsw_sp->bus_info->dev, "Port %d: Failed to init core port\n", 14108c2ecf20Sopenharmony_ci local_port); 14118c2ecf20Sopenharmony_ci return err; 14128c2ecf20Sopenharmony_ci } 14138c2ecf20Sopenharmony_ci 14148c2ecf20Sopenharmony_ci dev = alloc_etherdev(sizeof(struct mlxsw_sp_port)); 14158c2ecf20Sopenharmony_ci if (!dev) { 14168c2ecf20Sopenharmony_ci err = -ENOMEM; 14178c2ecf20Sopenharmony_ci goto err_alloc_etherdev; 14188c2ecf20Sopenharmony_ci } 14198c2ecf20Sopenharmony_ci SET_NETDEV_DEV(dev, mlxsw_sp->bus_info->dev); 14208c2ecf20Sopenharmony_ci dev_net_set(dev, mlxsw_sp_net(mlxsw_sp)); 14218c2ecf20Sopenharmony_ci mlxsw_sp_port = netdev_priv(dev); 14228c2ecf20Sopenharmony_ci mlxsw_sp_port->dev = dev; 14238c2ecf20Sopenharmony_ci mlxsw_sp_port->mlxsw_sp = mlxsw_sp; 14248c2ecf20Sopenharmony_ci mlxsw_sp_port->local_port = local_port; 14258c2ecf20Sopenharmony_ci mlxsw_sp_port->pvid = MLXSW_SP_DEFAULT_VID; 14268c2ecf20Sopenharmony_ci mlxsw_sp_port->split = split; 14278c2ecf20Sopenharmony_ci mlxsw_sp_port->split_base_local_port = split_base_local_port; 14288c2ecf20Sopenharmony_ci mlxsw_sp_port->mapping = *port_mapping; 14298c2ecf20Sopenharmony_ci mlxsw_sp_port->link.autoneg = 1; 14308c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&mlxsw_sp_port->vlans_list); 14318c2ecf20Sopenharmony_ci 14328c2ecf20Sopenharmony_ci mlxsw_sp_port->pcpu_stats = 14338c2ecf20Sopenharmony_ci netdev_alloc_pcpu_stats(struct mlxsw_sp_port_pcpu_stats); 14348c2ecf20Sopenharmony_ci if (!mlxsw_sp_port->pcpu_stats) { 14358c2ecf20Sopenharmony_ci err = -ENOMEM; 14368c2ecf20Sopenharmony_ci goto err_alloc_stats; 14378c2ecf20Sopenharmony_ci } 14388c2ecf20Sopenharmony_ci 14398c2ecf20Sopenharmony_ci INIT_DELAYED_WORK(&mlxsw_sp_port->periodic_hw_stats.update_dw, 14408c2ecf20Sopenharmony_ci &update_stats_cache); 14418c2ecf20Sopenharmony_ci 14428c2ecf20Sopenharmony_ci dev->netdev_ops = &mlxsw_sp_port_netdev_ops; 14438c2ecf20Sopenharmony_ci dev->ethtool_ops = &mlxsw_sp_port_ethtool_ops; 14448c2ecf20Sopenharmony_ci 14458c2ecf20Sopenharmony_ci err = mlxsw_sp_port_module_map(mlxsw_sp_port); 14468c2ecf20Sopenharmony_ci if (err) { 14478c2ecf20Sopenharmony_ci dev_err(mlxsw_sp->bus_info->dev, "Port %d: Failed to map module\n", 14488c2ecf20Sopenharmony_ci mlxsw_sp_port->local_port); 14498c2ecf20Sopenharmony_ci goto err_port_module_map; 14508c2ecf20Sopenharmony_ci } 14518c2ecf20Sopenharmony_ci 14528c2ecf20Sopenharmony_ci err = mlxsw_sp_port_swid_set(mlxsw_sp_port, 0); 14538c2ecf20Sopenharmony_ci if (err) { 14548c2ecf20Sopenharmony_ci dev_err(mlxsw_sp->bus_info->dev, "Port %d: Failed to set SWID\n", 14558c2ecf20Sopenharmony_ci mlxsw_sp_port->local_port); 14568c2ecf20Sopenharmony_ci goto err_port_swid_set; 14578c2ecf20Sopenharmony_ci } 14588c2ecf20Sopenharmony_ci 14598c2ecf20Sopenharmony_ci err = mlxsw_sp_port_dev_addr_init(mlxsw_sp_port); 14608c2ecf20Sopenharmony_ci if (err) { 14618c2ecf20Sopenharmony_ci dev_err(mlxsw_sp->bus_info->dev, "Port %d: Unable to init port mac address\n", 14628c2ecf20Sopenharmony_ci mlxsw_sp_port->local_port); 14638c2ecf20Sopenharmony_ci goto err_dev_addr_init; 14648c2ecf20Sopenharmony_ci } 14658c2ecf20Sopenharmony_ci 14668c2ecf20Sopenharmony_ci netif_carrier_off(dev); 14678c2ecf20Sopenharmony_ci 14688c2ecf20Sopenharmony_ci dev->features |= NETIF_F_NETNS_LOCAL | NETIF_F_LLTX | NETIF_F_SG | 14698c2ecf20Sopenharmony_ci NETIF_F_HW_VLAN_CTAG_FILTER | NETIF_F_HW_TC; 14708c2ecf20Sopenharmony_ci dev->hw_features |= NETIF_F_HW_TC | NETIF_F_LOOPBACK; 14718c2ecf20Sopenharmony_ci 14728c2ecf20Sopenharmony_ci dev->min_mtu = 0; 14738c2ecf20Sopenharmony_ci dev->max_mtu = ETH_MAX_MTU; 14748c2ecf20Sopenharmony_ci 14758c2ecf20Sopenharmony_ci /* Each packet needs to have a Tx header (metadata) on top all other 14768c2ecf20Sopenharmony_ci * headers. 14778c2ecf20Sopenharmony_ci */ 14788c2ecf20Sopenharmony_ci dev->needed_headroom = MLXSW_TXHDR_LEN; 14798c2ecf20Sopenharmony_ci 14808c2ecf20Sopenharmony_ci err = mlxsw_sp_port_system_port_mapping_set(mlxsw_sp_port); 14818c2ecf20Sopenharmony_ci if (err) { 14828c2ecf20Sopenharmony_ci dev_err(mlxsw_sp->bus_info->dev, "Port %d: Failed to set system port mapping\n", 14838c2ecf20Sopenharmony_ci mlxsw_sp_port->local_port); 14848c2ecf20Sopenharmony_ci goto err_port_system_port_mapping_set; 14858c2ecf20Sopenharmony_ci } 14868c2ecf20Sopenharmony_ci 14878c2ecf20Sopenharmony_ci err = mlxsw_sp_port_speed_by_width_set(mlxsw_sp_port); 14888c2ecf20Sopenharmony_ci if (err) { 14898c2ecf20Sopenharmony_ci dev_err(mlxsw_sp->bus_info->dev, "Port %d: Failed to enable speeds\n", 14908c2ecf20Sopenharmony_ci mlxsw_sp_port->local_port); 14918c2ecf20Sopenharmony_ci goto err_port_speed_by_width_set; 14928c2ecf20Sopenharmony_ci } 14938c2ecf20Sopenharmony_ci 14948c2ecf20Sopenharmony_ci err = mlxsw_sp->port_type_speed_ops->ptys_max_speed(mlxsw_sp_port, 14958c2ecf20Sopenharmony_ci &mlxsw_sp_port->max_speed); 14968c2ecf20Sopenharmony_ci if (err) { 14978c2ecf20Sopenharmony_ci dev_err(mlxsw_sp->bus_info->dev, "Port %d: Failed to get maximum speed\n", 14988c2ecf20Sopenharmony_ci mlxsw_sp_port->local_port); 14998c2ecf20Sopenharmony_ci goto err_max_speed_get; 15008c2ecf20Sopenharmony_ci } 15018c2ecf20Sopenharmony_ci 15028c2ecf20Sopenharmony_ci err = mlxsw_sp_port_max_mtu_get(mlxsw_sp_port, &mlxsw_sp_port->max_mtu); 15038c2ecf20Sopenharmony_ci if (err) { 15048c2ecf20Sopenharmony_ci dev_err(mlxsw_sp->bus_info->dev, "Port %d: Failed to get maximum MTU\n", 15058c2ecf20Sopenharmony_ci mlxsw_sp_port->local_port); 15068c2ecf20Sopenharmony_ci goto err_port_max_mtu_get; 15078c2ecf20Sopenharmony_ci } 15088c2ecf20Sopenharmony_ci 15098c2ecf20Sopenharmony_ci err = mlxsw_sp_port_mtu_set(mlxsw_sp_port, ETH_DATA_LEN); 15108c2ecf20Sopenharmony_ci if (err) { 15118c2ecf20Sopenharmony_ci dev_err(mlxsw_sp->bus_info->dev, "Port %d: Failed to set MTU\n", 15128c2ecf20Sopenharmony_ci mlxsw_sp_port->local_port); 15138c2ecf20Sopenharmony_ci goto err_port_mtu_set; 15148c2ecf20Sopenharmony_ci } 15158c2ecf20Sopenharmony_ci 15168c2ecf20Sopenharmony_ci err = mlxsw_sp_port_admin_status_set(mlxsw_sp_port, false); 15178c2ecf20Sopenharmony_ci if (err) 15188c2ecf20Sopenharmony_ci goto err_port_admin_status_set; 15198c2ecf20Sopenharmony_ci 15208c2ecf20Sopenharmony_ci err = mlxsw_sp_port_buffers_init(mlxsw_sp_port); 15218c2ecf20Sopenharmony_ci if (err) { 15228c2ecf20Sopenharmony_ci dev_err(mlxsw_sp->bus_info->dev, "Port %d: Failed to initialize buffers\n", 15238c2ecf20Sopenharmony_ci mlxsw_sp_port->local_port); 15248c2ecf20Sopenharmony_ci goto err_port_buffers_init; 15258c2ecf20Sopenharmony_ci } 15268c2ecf20Sopenharmony_ci 15278c2ecf20Sopenharmony_ci err = mlxsw_sp_port_ets_init(mlxsw_sp_port); 15288c2ecf20Sopenharmony_ci if (err) { 15298c2ecf20Sopenharmony_ci dev_err(mlxsw_sp->bus_info->dev, "Port %d: Failed to initialize ETS\n", 15308c2ecf20Sopenharmony_ci mlxsw_sp_port->local_port); 15318c2ecf20Sopenharmony_ci goto err_port_ets_init; 15328c2ecf20Sopenharmony_ci } 15338c2ecf20Sopenharmony_ci 15348c2ecf20Sopenharmony_ci err = mlxsw_sp_port_tc_mc_mode_set(mlxsw_sp_port, true); 15358c2ecf20Sopenharmony_ci if (err) { 15368c2ecf20Sopenharmony_ci dev_err(mlxsw_sp->bus_info->dev, "Port %d: Failed to initialize TC MC mode\n", 15378c2ecf20Sopenharmony_ci mlxsw_sp_port->local_port); 15388c2ecf20Sopenharmony_ci goto err_port_tc_mc_mode; 15398c2ecf20Sopenharmony_ci } 15408c2ecf20Sopenharmony_ci 15418c2ecf20Sopenharmony_ci /* ETS and buffers must be initialized before DCB. */ 15428c2ecf20Sopenharmony_ci err = mlxsw_sp_port_dcb_init(mlxsw_sp_port); 15438c2ecf20Sopenharmony_ci if (err) { 15448c2ecf20Sopenharmony_ci dev_err(mlxsw_sp->bus_info->dev, "Port %d: Failed to initialize DCB\n", 15458c2ecf20Sopenharmony_ci mlxsw_sp_port->local_port); 15468c2ecf20Sopenharmony_ci goto err_port_dcb_init; 15478c2ecf20Sopenharmony_ci } 15488c2ecf20Sopenharmony_ci 15498c2ecf20Sopenharmony_ci err = mlxsw_sp_port_fids_init(mlxsw_sp_port); 15508c2ecf20Sopenharmony_ci if (err) { 15518c2ecf20Sopenharmony_ci dev_err(mlxsw_sp->bus_info->dev, "Port %d: Failed to initialize FIDs\n", 15528c2ecf20Sopenharmony_ci mlxsw_sp_port->local_port); 15538c2ecf20Sopenharmony_ci goto err_port_fids_init; 15548c2ecf20Sopenharmony_ci } 15558c2ecf20Sopenharmony_ci 15568c2ecf20Sopenharmony_ci err = mlxsw_sp_tc_qdisc_init(mlxsw_sp_port); 15578c2ecf20Sopenharmony_ci if (err) { 15588c2ecf20Sopenharmony_ci dev_err(mlxsw_sp->bus_info->dev, "Port %d: Failed to initialize TC qdiscs\n", 15598c2ecf20Sopenharmony_ci mlxsw_sp_port->local_port); 15608c2ecf20Sopenharmony_ci goto err_port_qdiscs_init; 15618c2ecf20Sopenharmony_ci } 15628c2ecf20Sopenharmony_ci 15638c2ecf20Sopenharmony_ci err = mlxsw_sp_port_vlan_set(mlxsw_sp_port, 0, VLAN_N_VID - 1, false, 15648c2ecf20Sopenharmony_ci false); 15658c2ecf20Sopenharmony_ci if (err) { 15668c2ecf20Sopenharmony_ci dev_err(mlxsw_sp->bus_info->dev, "Port %d: Failed to clear VLAN filter\n", 15678c2ecf20Sopenharmony_ci mlxsw_sp_port->local_port); 15688c2ecf20Sopenharmony_ci goto err_port_vlan_clear; 15698c2ecf20Sopenharmony_ci } 15708c2ecf20Sopenharmony_ci 15718c2ecf20Sopenharmony_ci err = mlxsw_sp_port_nve_init(mlxsw_sp_port); 15728c2ecf20Sopenharmony_ci if (err) { 15738c2ecf20Sopenharmony_ci dev_err(mlxsw_sp->bus_info->dev, "Port %d: Failed to initialize NVE\n", 15748c2ecf20Sopenharmony_ci mlxsw_sp_port->local_port); 15758c2ecf20Sopenharmony_ci goto err_port_nve_init; 15768c2ecf20Sopenharmony_ci } 15778c2ecf20Sopenharmony_ci 15788c2ecf20Sopenharmony_ci err = mlxsw_sp_port_pvid_set(mlxsw_sp_port, MLXSW_SP_DEFAULT_VID); 15798c2ecf20Sopenharmony_ci if (err) { 15808c2ecf20Sopenharmony_ci dev_err(mlxsw_sp->bus_info->dev, "Port %d: Failed to set PVID\n", 15818c2ecf20Sopenharmony_ci mlxsw_sp_port->local_port); 15828c2ecf20Sopenharmony_ci goto err_port_pvid_set; 15838c2ecf20Sopenharmony_ci } 15848c2ecf20Sopenharmony_ci 15858c2ecf20Sopenharmony_ci mlxsw_sp_port_vlan = mlxsw_sp_port_vlan_create(mlxsw_sp_port, 15868c2ecf20Sopenharmony_ci MLXSW_SP_DEFAULT_VID); 15878c2ecf20Sopenharmony_ci if (IS_ERR(mlxsw_sp_port_vlan)) { 15888c2ecf20Sopenharmony_ci dev_err(mlxsw_sp->bus_info->dev, "Port %d: Failed to create VID 1\n", 15898c2ecf20Sopenharmony_ci mlxsw_sp_port->local_port); 15908c2ecf20Sopenharmony_ci err = PTR_ERR(mlxsw_sp_port_vlan); 15918c2ecf20Sopenharmony_ci goto err_port_vlan_create; 15928c2ecf20Sopenharmony_ci } 15938c2ecf20Sopenharmony_ci mlxsw_sp_port->default_vlan = mlxsw_sp_port_vlan; 15948c2ecf20Sopenharmony_ci 15958c2ecf20Sopenharmony_ci INIT_DELAYED_WORK(&mlxsw_sp_port->ptp.shaper_dw, 15968c2ecf20Sopenharmony_ci mlxsw_sp->ptp_ops->shaper_work); 15978c2ecf20Sopenharmony_ci 15988c2ecf20Sopenharmony_ci mlxsw_sp->ports[local_port] = mlxsw_sp_port; 15998c2ecf20Sopenharmony_ci 16008c2ecf20Sopenharmony_ci err = mlxsw_sp_port_overheat_init_val_set(mlxsw_sp_port); 16018c2ecf20Sopenharmony_ci if (err) { 16028c2ecf20Sopenharmony_ci dev_err(mlxsw_sp->bus_info->dev, "Port %d: Failed to set overheat initial value\n", 16038c2ecf20Sopenharmony_ci mlxsw_sp_port->local_port); 16048c2ecf20Sopenharmony_ci goto err_port_overheat_init_val_set; 16058c2ecf20Sopenharmony_ci } 16068c2ecf20Sopenharmony_ci 16078c2ecf20Sopenharmony_ci err = register_netdev(dev); 16088c2ecf20Sopenharmony_ci if (err) { 16098c2ecf20Sopenharmony_ci dev_err(mlxsw_sp->bus_info->dev, "Port %d: Failed to register netdev\n", 16108c2ecf20Sopenharmony_ci mlxsw_sp_port->local_port); 16118c2ecf20Sopenharmony_ci goto err_register_netdev; 16128c2ecf20Sopenharmony_ci } 16138c2ecf20Sopenharmony_ci 16148c2ecf20Sopenharmony_ci mlxsw_core_port_eth_set(mlxsw_sp->core, mlxsw_sp_port->local_port, 16158c2ecf20Sopenharmony_ci mlxsw_sp_port, dev); 16168c2ecf20Sopenharmony_ci mlxsw_core_schedule_dw(&mlxsw_sp_port->periodic_hw_stats.update_dw, 0); 16178c2ecf20Sopenharmony_ci return 0; 16188c2ecf20Sopenharmony_ci 16198c2ecf20Sopenharmony_cierr_register_netdev: 16208c2ecf20Sopenharmony_cierr_port_overheat_init_val_set: 16218c2ecf20Sopenharmony_ci mlxsw_sp->ports[local_port] = NULL; 16228c2ecf20Sopenharmony_ci mlxsw_sp_port_vlan_destroy(mlxsw_sp_port_vlan); 16238c2ecf20Sopenharmony_cierr_port_vlan_create: 16248c2ecf20Sopenharmony_cierr_port_pvid_set: 16258c2ecf20Sopenharmony_ci mlxsw_sp_port_nve_fini(mlxsw_sp_port); 16268c2ecf20Sopenharmony_cierr_port_nve_init: 16278c2ecf20Sopenharmony_cierr_port_vlan_clear: 16288c2ecf20Sopenharmony_ci mlxsw_sp_tc_qdisc_fini(mlxsw_sp_port); 16298c2ecf20Sopenharmony_cierr_port_qdiscs_init: 16308c2ecf20Sopenharmony_ci mlxsw_sp_port_fids_fini(mlxsw_sp_port); 16318c2ecf20Sopenharmony_cierr_port_fids_init: 16328c2ecf20Sopenharmony_ci mlxsw_sp_port_dcb_fini(mlxsw_sp_port); 16338c2ecf20Sopenharmony_cierr_port_dcb_init: 16348c2ecf20Sopenharmony_ci mlxsw_sp_port_tc_mc_mode_set(mlxsw_sp_port, false); 16358c2ecf20Sopenharmony_cierr_port_tc_mc_mode: 16368c2ecf20Sopenharmony_cierr_port_ets_init: 16378c2ecf20Sopenharmony_ci mlxsw_sp_port_buffers_fini(mlxsw_sp_port); 16388c2ecf20Sopenharmony_cierr_port_buffers_init: 16398c2ecf20Sopenharmony_cierr_port_admin_status_set: 16408c2ecf20Sopenharmony_cierr_port_mtu_set: 16418c2ecf20Sopenharmony_cierr_port_max_mtu_get: 16428c2ecf20Sopenharmony_cierr_max_speed_get: 16438c2ecf20Sopenharmony_cierr_port_speed_by_width_set: 16448c2ecf20Sopenharmony_cierr_port_system_port_mapping_set: 16458c2ecf20Sopenharmony_cierr_dev_addr_init: 16468c2ecf20Sopenharmony_ci mlxsw_sp_port_swid_set(mlxsw_sp_port, MLXSW_PORT_SWID_DISABLED_PORT); 16478c2ecf20Sopenharmony_cierr_port_swid_set: 16488c2ecf20Sopenharmony_ci mlxsw_sp_port_module_unmap(mlxsw_sp_port); 16498c2ecf20Sopenharmony_cierr_port_module_map: 16508c2ecf20Sopenharmony_ci free_percpu(mlxsw_sp_port->pcpu_stats); 16518c2ecf20Sopenharmony_cierr_alloc_stats: 16528c2ecf20Sopenharmony_ci free_netdev(dev); 16538c2ecf20Sopenharmony_cierr_alloc_etherdev: 16548c2ecf20Sopenharmony_ci mlxsw_core_port_fini(mlxsw_sp->core, local_port); 16558c2ecf20Sopenharmony_ci return err; 16568c2ecf20Sopenharmony_ci} 16578c2ecf20Sopenharmony_ci 16588c2ecf20Sopenharmony_cistatic void mlxsw_sp_port_remove(struct mlxsw_sp *mlxsw_sp, u8 local_port) 16598c2ecf20Sopenharmony_ci{ 16608c2ecf20Sopenharmony_ci struct mlxsw_sp_port *mlxsw_sp_port = mlxsw_sp->ports[local_port]; 16618c2ecf20Sopenharmony_ci 16628c2ecf20Sopenharmony_ci cancel_delayed_work_sync(&mlxsw_sp_port->periodic_hw_stats.update_dw); 16638c2ecf20Sopenharmony_ci cancel_delayed_work_sync(&mlxsw_sp_port->ptp.shaper_dw); 16648c2ecf20Sopenharmony_ci mlxsw_sp_port_ptp_clear(mlxsw_sp_port); 16658c2ecf20Sopenharmony_ci mlxsw_core_port_clear(mlxsw_sp->core, local_port, mlxsw_sp); 16668c2ecf20Sopenharmony_ci unregister_netdev(mlxsw_sp_port->dev); /* This calls ndo_stop */ 16678c2ecf20Sopenharmony_ci mlxsw_sp->ports[local_port] = NULL; 16688c2ecf20Sopenharmony_ci mlxsw_sp_port_vlan_flush(mlxsw_sp_port, true); 16698c2ecf20Sopenharmony_ci mlxsw_sp_port_nve_fini(mlxsw_sp_port); 16708c2ecf20Sopenharmony_ci mlxsw_sp_tc_qdisc_fini(mlxsw_sp_port); 16718c2ecf20Sopenharmony_ci mlxsw_sp_port_fids_fini(mlxsw_sp_port); 16728c2ecf20Sopenharmony_ci mlxsw_sp_port_dcb_fini(mlxsw_sp_port); 16738c2ecf20Sopenharmony_ci mlxsw_sp_port_tc_mc_mode_set(mlxsw_sp_port, false); 16748c2ecf20Sopenharmony_ci mlxsw_sp_port_buffers_fini(mlxsw_sp_port); 16758c2ecf20Sopenharmony_ci mlxsw_sp_port_swid_set(mlxsw_sp_port, MLXSW_PORT_SWID_DISABLED_PORT); 16768c2ecf20Sopenharmony_ci mlxsw_sp_port_module_unmap(mlxsw_sp_port); 16778c2ecf20Sopenharmony_ci free_percpu(mlxsw_sp_port->pcpu_stats); 16788c2ecf20Sopenharmony_ci WARN_ON_ONCE(!list_empty(&mlxsw_sp_port->vlans_list)); 16798c2ecf20Sopenharmony_ci free_netdev(mlxsw_sp_port->dev); 16808c2ecf20Sopenharmony_ci mlxsw_core_port_fini(mlxsw_sp->core, local_port); 16818c2ecf20Sopenharmony_ci} 16828c2ecf20Sopenharmony_ci 16838c2ecf20Sopenharmony_cistatic int mlxsw_sp_cpu_port_create(struct mlxsw_sp *mlxsw_sp) 16848c2ecf20Sopenharmony_ci{ 16858c2ecf20Sopenharmony_ci struct mlxsw_sp_port *mlxsw_sp_port; 16868c2ecf20Sopenharmony_ci int err; 16878c2ecf20Sopenharmony_ci 16888c2ecf20Sopenharmony_ci mlxsw_sp_port = kzalloc(sizeof(*mlxsw_sp_port), GFP_KERNEL); 16898c2ecf20Sopenharmony_ci if (!mlxsw_sp_port) 16908c2ecf20Sopenharmony_ci return -ENOMEM; 16918c2ecf20Sopenharmony_ci 16928c2ecf20Sopenharmony_ci mlxsw_sp_port->mlxsw_sp = mlxsw_sp; 16938c2ecf20Sopenharmony_ci mlxsw_sp_port->local_port = MLXSW_PORT_CPU_PORT; 16948c2ecf20Sopenharmony_ci 16958c2ecf20Sopenharmony_ci err = mlxsw_core_cpu_port_init(mlxsw_sp->core, 16968c2ecf20Sopenharmony_ci mlxsw_sp_port, 16978c2ecf20Sopenharmony_ci mlxsw_sp->base_mac, 16988c2ecf20Sopenharmony_ci sizeof(mlxsw_sp->base_mac)); 16998c2ecf20Sopenharmony_ci if (err) { 17008c2ecf20Sopenharmony_ci dev_err(mlxsw_sp->bus_info->dev, "Failed to initialize core CPU port\n"); 17018c2ecf20Sopenharmony_ci goto err_core_cpu_port_init; 17028c2ecf20Sopenharmony_ci } 17038c2ecf20Sopenharmony_ci 17048c2ecf20Sopenharmony_ci mlxsw_sp->ports[MLXSW_PORT_CPU_PORT] = mlxsw_sp_port; 17058c2ecf20Sopenharmony_ci return 0; 17068c2ecf20Sopenharmony_ci 17078c2ecf20Sopenharmony_cierr_core_cpu_port_init: 17088c2ecf20Sopenharmony_ci kfree(mlxsw_sp_port); 17098c2ecf20Sopenharmony_ci return err; 17108c2ecf20Sopenharmony_ci} 17118c2ecf20Sopenharmony_ci 17128c2ecf20Sopenharmony_cistatic void mlxsw_sp_cpu_port_remove(struct mlxsw_sp *mlxsw_sp) 17138c2ecf20Sopenharmony_ci{ 17148c2ecf20Sopenharmony_ci struct mlxsw_sp_port *mlxsw_sp_port = 17158c2ecf20Sopenharmony_ci mlxsw_sp->ports[MLXSW_PORT_CPU_PORT]; 17168c2ecf20Sopenharmony_ci 17178c2ecf20Sopenharmony_ci mlxsw_core_cpu_port_fini(mlxsw_sp->core); 17188c2ecf20Sopenharmony_ci mlxsw_sp->ports[MLXSW_PORT_CPU_PORT] = NULL; 17198c2ecf20Sopenharmony_ci kfree(mlxsw_sp_port); 17208c2ecf20Sopenharmony_ci} 17218c2ecf20Sopenharmony_ci 17228c2ecf20Sopenharmony_cistatic bool mlxsw_sp_port_created(struct mlxsw_sp *mlxsw_sp, u8 local_port) 17238c2ecf20Sopenharmony_ci{ 17248c2ecf20Sopenharmony_ci return mlxsw_sp->ports[local_port] != NULL; 17258c2ecf20Sopenharmony_ci} 17268c2ecf20Sopenharmony_ci 17278c2ecf20Sopenharmony_cistatic void mlxsw_sp_ports_remove(struct mlxsw_sp *mlxsw_sp) 17288c2ecf20Sopenharmony_ci{ 17298c2ecf20Sopenharmony_ci int i; 17308c2ecf20Sopenharmony_ci 17318c2ecf20Sopenharmony_ci for (i = 1; i < mlxsw_core_max_ports(mlxsw_sp->core); i++) 17328c2ecf20Sopenharmony_ci if (mlxsw_sp_port_created(mlxsw_sp, i)) 17338c2ecf20Sopenharmony_ci mlxsw_sp_port_remove(mlxsw_sp, i); 17348c2ecf20Sopenharmony_ci mlxsw_sp_cpu_port_remove(mlxsw_sp); 17358c2ecf20Sopenharmony_ci kfree(mlxsw_sp->ports); 17368c2ecf20Sopenharmony_ci mlxsw_sp->ports = NULL; 17378c2ecf20Sopenharmony_ci} 17388c2ecf20Sopenharmony_ci 17398c2ecf20Sopenharmony_cistatic int mlxsw_sp_ports_create(struct mlxsw_sp *mlxsw_sp) 17408c2ecf20Sopenharmony_ci{ 17418c2ecf20Sopenharmony_ci unsigned int max_ports = mlxsw_core_max_ports(mlxsw_sp->core); 17428c2ecf20Sopenharmony_ci struct mlxsw_sp_port_mapping *port_mapping; 17438c2ecf20Sopenharmony_ci size_t alloc_size; 17448c2ecf20Sopenharmony_ci int i; 17458c2ecf20Sopenharmony_ci int err; 17468c2ecf20Sopenharmony_ci 17478c2ecf20Sopenharmony_ci alloc_size = sizeof(struct mlxsw_sp_port *) * max_ports; 17488c2ecf20Sopenharmony_ci mlxsw_sp->ports = kzalloc(alloc_size, GFP_KERNEL); 17498c2ecf20Sopenharmony_ci if (!mlxsw_sp->ports) 17508c2ecf20Sopenharmony_ci return -ENOMEM; 17518c2ecf20Sopenharmony_ci 17528c2ecf20Sopenharmony_ci err = mlxsw_sp_cpu_port_create(mlxsw_sp); 17538c2ecf20Sopenharmony_ci if (err) 17548c2ecf20Sopenharmony_ci goto err_cpu_port_create; 17558c2ecf20Sopenharmony_ci 17568c2ecf20Sopenharmony_ci for (i = 1; i < max_ports; i++) { 17578c2ecf20Sopenharmony_ci port_mapping = mlxsw_sp->port_mapping[i]; 17588c2ecf20Sopenharmony_ci if (!port_mapping) 17598c2ecf20Sopenharmony_ci continue; 17608c2ecf20Sopenharmony_ci err = mlxsw_sp_port_create(mlxsw_sp, i, 0, port_mapping); 17618c2ecf20Sopenharmony_ci if (err) 17628c2ecf20Sopenharmony_ci goto err_port_create; 17638c2ecf20Sopenharmony_ci } 17648c2ecf20Sopenharmony_ci return 0; 17658c2ecf20Sopenharmony_ci 17668c2ecf20Sopenharmony_cierr_port_create: 17678c2ecf20Sopenharmony_ci for (i--; i >= 1; i--) 17688c2ecf20Sopenharmony_ci if (mlxsw_sp_port_created(mlxsw_sp, i)) 17698c2ecf20Sopenharmony_ci mlxsw_sp_port_remove(mlxsw_sp, i); 17708c2ecf20Sopenharmony_ci mlxsw_sp_cpu_port_remove(mlxsw_sp); 17718c2ecf20Sopenharmony_cierr_cpu_port_create: 17728c2ecf20Sopenharmony_ci kfree(mlxsw_sp->ports); 17738c2ecf20Sopenharmony_ci mlxsw_sp->ports = NULL; 17748c2ecf20Sopenharmony_ci return err; 17758c2ecf20Sopenharmony_ci} 17768c2ecf20Sopenharmony_ci 17778c2ecf20Sopenharmony_cistatic int mlxsw_sp_port_module_info_init(struct mlxsw_sp *mlxsw_sp) 17788c2ecf20Sopenharmony_ci{ 17798c2ecf20Sopenharmony_ci unsigned int max_ports = mlxsw_core_max_ports(mlxsw_sp->core); 17808c2ecf20Sopenharmony_ci struct mlxsw_sp_port_mapping port_mapping; 17818c2ecf20Sopenharmony_ci int i; 17828c2ecf20Sopenharmony_ci int err; 17838c2ecf20Sopenharmony_ci 17848c2ecf20Sopenharmony_ci mlxsw_sp->port_mapping = kcalloc(max_ports, 17858c2ecf20Sopenharmony_ci sizeof(struct mlxsw_sp_port_mapping *), 17868c2ecf20Sopenharmony_ci GFP_KERNEL); 17878c2ecf20Sopenharmony_ci if (!mlxsw_sp->port_mapping) 17888c2ecf20Sopenharmony_ci return -ENOMEM; 17898c2ecf20Sopenharmony_ci 17908c2ecf20Sopenharmony_ci for (i = 1; i < max_ports; i++) { 17918c2ecf20Sopenharmony_ci err = mlxsw_sp_port_module_info_get(mlxsw_sp, i, &port_mapping); 17928c2ecf20Sopenharmony_ci if (err) 17938c2ecf20Sopenharmony_ci goto err_port_module_info_get; 17948c2ecf20Sopenharmony_ci if (!port_mapping.width) 17958c2ecf20Sopenharmony_ci continue; 17968c2ecf20Sopenharmony_ci 17978c2ecf20Sopenharmony_ci mlxsw_sp->port_mapping[i] = kmemdup(&port_mapping, 17988c2ecf20Sopenharmony_ci sizeof(port_mapping), 17998c2ecf20Sopenharmony_ci GFP_KERNEL); 18008c2ecf20Sopenharmony_ci if (!mlxsw_sp->port_mapping[i]) { 18018c2ecf20Sopenharmony_ci err = -ENOMEM; 18028c2ecf20Sopenharmony_ci goto err_port_module_info_dup; 18038c2ecf20Sopenharmony_ci } 18048c2ecf20Sopenharmony_ci } 18058c2ecf20Sopenharmony_ci return 0; 18068c2ecf20Sopenharmony_ci 18078c2ecf20Sopenharmony_cierr_port_module_info_get: 18088c2ecf20Sopenharmony_cierr_port_module_info_dup: 18098c2ecf20Sopenharmony_ci for (i--; i >= 1; i--) 18108c2ecf20Sopenharmony_ci kfree(mlxsw_sp->port_mapping[i]); 18118c2ecf20Sopenharmony_ci kfree(mlxsw_sp->port_mapping); 18128c2ecf20Sopenharmony_ci return err; 18138c2ecf20Sopenharmony_ci} 18148c2ecf20Sopenharmony_ci 18158c2ecf20Sopenharmony_cistatic void mlxsw_sp_port_module_info_fini(struct mlxsw_sp *mlxsw_sp) 18168c2ecf20Sopenharmony_ci{ 18178c2ecf20Sopenharmony_ci int i; 18188c2ecf20Sopenharmony_ci 18198c2ecf20Sopenharmony_ci for (i = 1; i < mlxsw_core_max_ports(mlxsw_sp->core); i++) 18208c2ecf20Sopenharmony_ci kfree(mlxsw_sp->port_mapping[i]); 18218c2ecf20Sopenharmony_ci kfree(mlxsw_sp->port_mapping); 18228c2ecf20Sopenharmony_ci} 18238c2ecf20Sopenharmony_ci 18248c2ecf20Sopenharmony_cistatic u8 mlxsw_sp_cluster_base_port_get(u8 local_port, unsigned int max_width) 18258c2ecf20Sopenharmony_ci{ 18268c2ecf20Sopenharmony_ci u8 offset = (local_port - 1) % max_width; 18278c2ecf20Sopenharmony_ci 18288c2ecf20Sopenharmony_ci return local_port - offset; 18298c2ecf20Sopenharmony_ci} 18308c2ecf20Sopenharmony_ci 18318c2ecf20Sopenharmony_cistatic int 18328c2ecf20Sopenharmony_cimlxsw_sp_port_split_create(struct mlxsw_sp *mlxsw_sp, u8 base_port, 18338c2ecf20Sopenharmony_ci struct mlxsw_sp_port_mapping *port_mapping, 18348c2ecf20Sopenharmony_ci unsigned int count, u8 offset) 18358c2ecf20Sopenharmony_ci{ 18368c2ecf20Sopenharmony_ci struct mlxsw_sp_port_mapping split_port_mapping; 18378c2ecf20Sopenharmony_ci int err, i; 18388c2ecf20Sopenharmony_ci 18398c2ecf20Sopenharmony_ci split_port_mapping = *port_mapping; 18408c2ecf20Sopenharmony_ci split_port_mapping.width /= count; 18418c2ecf20Sopenharmony_ci for (i = 0; i < count; i++) { 18428c2ecf20Sopenharmony_ci err = mlxsw_sp_port_create(mlxsw_sp, base_port + i * offset, 18438c2ecf20Sopenharmony_ci base_port, &split_port_mapping); 18448c2ecf20Sopenharmony_ci if (err) 18458c2ecf20Sopenharmony_ci goto err_port_create; 18468c2ecf20Sopenharmony_ci split_port_mapping.lane += split_port_mapping.width; 18478c2ecf20Sopenharmony_ci } 18488c2ecf20Sopenharmony_ci 18498c2ecf20Sopenharmony_ci return 0; 18508c2ecf20Sopenharmony_ci 18518c2ecf20Sopenharmony_cierr_port_create: 18528c2ecf20Sopenharmony_ci for (i--; i >= 0; i--) 18538c2ecf20Sopenharmony_ci if (mlxsw_sp_port_created(mlxsw_sp, base_port + i * offset)) 18548c2ecf20Sopenharmony_ci mlxsw_sp_port_remove(mlxsw_sp, base_port + i * offset); 18558c2ecf20Sopenharmony_ci return err; 18568c2ecf20Sopenharmony_ci} 18578c2ecf20Sopenharmony_ci 18588c2ecf20Sopenharmony_cistatic void mlxsw_sp_port_unsplit_create(struct mlxsw_sp *mlxsw_sp, 18598c2ecf20Sopenharmony_ci u8 base_port, 18608c2ecf20Sopenharmony_ci unsigned int count, u8 offset) 18618c2ecf20Sopenharmony_ci{ 18628c2ecf20Sopenharmony_ci struct mlxsw_sp_port_mapping *port_mapping; 18638c2ecf20Sopenharmony_ci int i; 18648c2ecf20Sopenharmony_ci 18658c2ecf20Sopenharmony_ci /* Go over original unsplit ports in the gap and recreate them. */ 18668c2ecf20Sopenharmony_ci for (i = 0; i < count * offset; i++) { 18678c2ecf20Sopenharmony_ci port_mapping = mlxsw_sp->port_mapping[base_port + i]; 18688c2ecf20Sopenharmony_ci if (!port_mapping) 18698c2ecf20Sopenharmony_ci continue; 18708c2ecf20Sopenharmony_ci mlxsw_sp_port_create(mlxsw_sp, base_port + i, 0, port_mapping); 18718c2ecf20Sopenharmony_ci } 18728c2ecf20Sopenharmony_ci} 18738c2ecf20Sopenharmony_ci 18748c2ecf20Sopenharmony_cistatic int mlxsw_sp_local_ports_offset(struct mlxsw_core *mlxsw_core, 18758c2ecf20Sopenharmony_ci unsigned int count, 18768c2ecf20Sopenharmony_ci unsigned int max_width) 18778c2ecf20Sopenharmony_ci{ 18788c2ecf20Sopenharmony_ci enum mlxsw_res_id local_ports_in_x_res_id; 18798c2ecf20Sopenharmony_ci int split_width = max_width / count; 18808c2ecf20Sopenharmony_ci 18818c2ecf20Sopenharmony_ci if (split_width == 1) 18828c2ecf20Sopenharmony_ci local_ports_in_x_res_id = MLXSW_RES_ID_LOCAL_PORTS_IN_1X; 18838c2ecf20Sopenharmony_ci else if (split_width == 2) 18848c2ecf20Sopenharmony_ci local_ports_in_x_res_id = MLXSW_RES_ID_LOCAL_PORTS_IN_2X; 18858c2ecf20Sopenharmony_ci else if (split_width == 4) 18868c2ecf20Sopenharmony_ci local_ports_in_x_res_id = MLXSW_RES_ID_LOCAL_PORTS_IN_4X; 18878c2ecf20Sopenharmony_ci else 18888c2ecf20Sopenharmony_ci return -EINVAL; 18898c2ecf20Sopenharmony_ci 18908c2ecf20Sopenharmony_ci if (!mlxsw_core_res_valid(mlxsw_core, local_ports_in_x_res_id)) 18918c2ecf20Sopenharmony_ci return -EINVAL; 18928c2ecf20Sopenharmony_ci return mlxsw_core_res_get(mlxsw_core, local_ports_in_x_res_id); 18938c2ecf20Sopenharmony_ci} 18948c2ecf20Sopenharmony_ci 18958c2ecf20Sopenharmony_cistatic struct mlxsw_sp_port * 18968c2ecf20Sopenharmony_cimlxsw_sp_port_get_by_local_port(struct mlxsw_sp *mlxsw_sp, u8 local_port) 18978c2ecf20Sopenharmony_ci{ 18988c2ecf20Sopenharmony_ci if (mlxsw_sp->ports && mlxsw_sp->ports[local_port]) 18998c2ecf20Sopenharmony_ci return mlxsw_sp->ports[local_port]; 19008c2ecf20Sopenharmony_ci return NULL; 19018c2ecf20Sopenharmony_ci} 19028c2ecf20Sopenharmony_ci 19038c2ecf20Sopenharmony_cistatic int mlxsw_sp_port_split(struct mlxsw_core *mlxsw_core, u8 local_port, 19048c2ecf20Sopenharmony_ci unsigned int count, 19058c2ecf20Sopenharmony_ci struct netlink_ext_ack *extack) 19068c2ecf20Sopenharmony_ci{ 19078c2ecf20Sopenharmony_ci struct mlxsw_sp *mlxsw_sp = mlxsw_core_driver_priv(mlxsw_core); 19088c2ecf20Sopenharmony_ci struct mlxsw_sp_port_mapping port_mapping; 19098c2ecf20Sopenharmony_ci struct mlxsw_sp_port *mlxsw_sp_port; 19108c2ecf20Sopenharmony_ci int max_width; 19118c2ecf20Sopenharmony_ci u8 base_port; 19128c2ecf20Sopenharmony_ci int offset; 19138c2ecf20Sopenharmony_ci int i; 19148c2ecf20Sopenharmony_ci int err; 19158c2ecf20Sopenharmony_ci 19168c2ecf20Sopenharmony_ci mlxsw_sp_port = mlxsw_sp_port_get_by_local_port(mlxsw_sp, local_port); 19178c2ecf20Sopenharmony_ci if (!mlxsw_sp_port) { 19188c2ecf20Sopenharmony_ci dev_err(mlxsw_sp->bus_info->dev, "Port number \"%d\" does not exist\n", 19198c2ecf20Sopenharmony_ci local_port); 19208c2ecf20Sopenharmony_ci NL_SET_ERR_MSG_MOD(extack, "Port number does not exist"); 19218c2ecf20Sopenharmony_ci return -EINVAL; 19228c2ecf20Sopenharmony_ci } 19238c2ecf20Sopenharmony_ci 19248c2ecf20Sopenharmony_ci max_width = mlxsw_core_module_max_width(mlxsw_core, 19258c2ecf20Sopenharmony_ci mlxsw_sp_port->mapping.module); 19268c2ecf20Sopenharmony_ci if (max_width < 0) { 19278c2ecf20Sopenharmony_ci netdev_err(mlxsw_sp_port->dev, "Cannot get max width of port module\n"); 19288c2ecf20Sopenharmony_ci NL_SET_ERR_MSG_MOD(extack, "Cannot get max width of port module"); 19298c2ecf20Sopenharmony_ci return max_width; 19308c2ecf20Sopenharmony_ci } 19318c2ecf20Sopenharmony_ci 19328c2ecf20Sopenharmony_ci /* Split port with non-max cannot be split. */ 19338c2ecf20Sopenharmony_ci if (mlxsw_sp_port->mapping.width != max_width) { 19348c2ecf20Sopenharmony_ci netdev_err(mlxsw_sp_port->dev, "Port cannot be split\n"); 19358c2ecf20Sopenharmony_ci NL_SET_ERR_MSG_MOD(extack, "Port cannot be split"); 19368c2ecf20Sopenharmony_ci return -EINVAL; 19378c2ecf20Sopenharmony_ci } 19388c2ecf20Sopenharmony_ci 19398c2ecf20Sopenharmony_ci offset = mlxsw_sp_local_ports_offset(mlxsw_core, count, max_width); 19408c2ecf20Sopenharmony_ci if (offset < 0) { 19418c2ecf20Sopenharmony_ci netdev_err(mlxsw_sp_port->dev, "Cannot obtain local port offset\n"); 19428c2ecf20Sopenharmony_ci NL_SET_ERR_MSG_MOD(extack, "Cannot obtain local port offset"); 19438c2ecf20Sopenharmony_ci return -EINVAL; 19448c2ecf20Sopenharmony_ci } 19458c2ecf20Sopenharmony_ci 19468c2ecf20Sopenharmony_ci /* Only in case max split is being done, the local port and 19478c2ecf20Sopenharmony_ci * base port may differ. 19488c2ecf20Sopenharmony_ci */ 19498c2ecf20Sopenharmony_ci base_port = count == max_width ? 19508c2ecf20Sopenharmony_ci mlxsw_sp_cluster_base_port_get(local_port, max_width) : 19518c2ecf20Sopenharmony_ci local_port; 19528c2ecf20Sopenharmony_ci 19538c2ecf20Sopenharmony_ci for (i = 0; i < count * offset; i++) { 19548c2ecf20Sopenharmony_ci /* Expect base port to exist and also the one in the middle in 19558c2ecf20Sopenharmony_ci * case of maximal split count. 19568c2ecf20Sopenharmony_ci */ 19578c2ecf20Sopenharmony_ci if (i == 0 || (count == max_width && i == count / 2)) 19588c2ecf20Sopenharmony_ci continue; 19598c2ecf20Sopenharmony_ci 19608c2ecf20Sopenharmony_ci if (mlxsw_sp_port_created(mlxsw_sp, base_port + i)) { 19618c2ecf20Sopenharmony_ci netdev_err(mlxsw_sp_port->dev, "Invalid split configuration\n"); 19628c2ecf20Sopenharmony_ci NL_SET_ERR_MSG_MOD(extack, "Invalid split configuration"); 19638c2ecf20Sopenharmony_ci return -EINVAL; 19648c2ecf20Sopenharmony_ci } 19658c2ecf20Sopenharmony_ci } 19668c2ecf20Sopenharmony_ci 19678c2ecf20Sopenharmony_ci port_mapping = mlxsw_sp_port->mapping; 19688c2ecf20Sopenharmony_ci 19698c2ecf20Sopenharmony_ci for (i = 0; i < count; i++) 19708c2ecf20Sopenharmony_ci if (mlxsw_sp_port_created(mlxsw_sp, base_port + i * offset)) 19718c2ecf20Sopenharmony_ci mlxsw_sp_port_remove(mlxsw_sp, base_port + i * offset); 19728c2ecf20Sopenharmony_ci 19738c2ecf20Sopenharmony_ci err = mlxsw_sp_port_split_create(mlxsw_sp, base_port, &port_mapping, 19748c2ecf20Sopenharmony_ci count, offset); 19758c2ecf20Sopenharmony_ci if (err) { 19768c2ecf20Sopenharmony_ci dev_err(mlxsw_sp->bus_info->dev, "Failed to create split ports\n"); 19778c2ecf20Sopenharmony_ci goto err_port_split_create; 19788c2ecf20Sopenharmony_ci } 19798c2ecf20Sopenharmony_ci 19808c2ecf20Sopenharmony_ci return 0; 19818c2ecf20Sopenharmony_ci 19828c2ecf20Sopenharmony_cierr_port_split_create: 19838c2ecf20Sopenharmony_ci mlxsw_sp_port_unsplit_create(mlxsw_sp, base_port, count, offset); 19848c2ecf20Sopenharmony_ci return err; 19858c2ecf20Sopenharmony_ci} 19868c2ecf20Sopenharmony_ci 19878c2ecf20Sopenharmony_cistatic int mlxsw_sp_port_unsplit(struct mlxsw_core *mlxsw_core, u8 local_port, 19888c2ecf20Sopenharmony_ci struct netlink_ext_ack *extack) 19898c2ecf20Sopenharmony_ci{ 19908c2ecf20Sopenharmony_ci struct mlxsw_sp *mlxsw_sp = mlxsw_core_driver_priv(mlxsw_core); 19918c2ecf20Sopenharmony_ci struct mlxsw_sp_port *mlxsw_sp_port; 19928c2ecf20Sopenharmony_ci unsigned int count; 19938c2ecf20Sopenharmony_ci int max_width; 19948c2ecf20Sopenharmony_ci u8 base_port; 19958c2ecf20Sopenharmony_ci int offset; 19968c2ecf20Sopenharmony_ci int i; 19978c2ecf20Sopenharmony_ci 19988c2ecf20Sopenharmony_ci mlxsw_sp_port = mlxsw_sp_port_get_by_local_port(mlxsw_sp, local_port); 19998c2ecf20Sopenharmony_ci if (!mlxsw_sp_port) { 20008c2ecf20Sopenharmony_ci dev_err(mlxsw_sp->bus_info->dev, "Port number \"%d\" does not exist\n", 20018c2ecf20Sopenharmony_ci local_port); 20028c2ecf20Sopenharmony_ci NL_SET_ERR_MSG_MOD(extack, "Port number does not exist"); 20038c2ecf20Sopenharmony_ci return -EINVAL; 20048c2ecf20Sopenharmony_ci } 20058c2ecf20Sopenharmony_ci 20068c2ecf20Sopenharmony_ci if (!mlxsw_sp_port->split) { 20078c2ecf20Sopenharmony_ci netdev_err(mlxsw_sp_port->dev, "Port was not split\n"); 20088c2ecf20Sopenharmony_ci NL_SET_ERR_MSG_MOD(extack, "Port was not split"); 20098c2ecf20Sopenharmony_ci return -EINVAL; 20108c2ecf20Sopenharmony_ci } 20118c2ecf20Sopenharmony_ci 20128c2ecf20Sopenharmony_ci max_width = mlxsw_core_module_max_width(mlxsw_core, 20138c2ecf20Sopenharmony_ci mlxsw_sp_port->mapping.module); 20148c2ecf20Sopenharmony_ci if (max_width < 0) { 20158c2ecf20Sopenharmony_ci netdev_err(mlxsw_sp_port->dev, "Cannot get max width of port module\n"); 20168c2ecf20Sopenharmony_ci NL_SET_ERR_MSG_MOD(extack, "Cannot get max width of port module"); 20178c2ecf20Sopenharmony_ci return max_width; 20188c2ecf20Sopenharmony_ci } 20198c2ecf20Sopenharmony_ci 20208c2ecf20Sopenharmony_ci count = max_width / mlxsw_sp_port->mapping.width; 20218c2ecf20Sopenharmony_ci 20228c2ecf20Sopenharmony_ci offset = mlxsw_sp_local_ports_offset(mlxsw_core, count, max_width); 20238c2ecf20Sopenharmony_ci if (WARN_ON(offset < 0)) { 20248c2ecf20Sopenharmony_ci netdev_err(mlxsw_sp_port->dev, "Cannot obtain local port offset\n"); 20258c2ecf20Sopenharmony_ci NL_SET_ERR_MSG_MOD(extack, "Cannot obtain local port offset"); 20268c2ecf20Sopenharmony_ci return -EINVAL; 20278c2ecf20Sopenharmony_ci } 20288c2ecf20Sopenharmony_ci 20298c2ecf20Sopenharmony_ci base_port = mlxsw_sp_port->split_base_local_port; 20308c2ecf20Sopenharmony_ci 20318c2ecf20Sopenharmony_ci for (i = 0; i < count; i++) 20328c2ecf20Sopenharmony_ci if (mlxsw_sp_port_created(mlxsw_sp, base_port + i * offset)) 20338c2ecf20Sopenharmony_ci mlxsw_sp_port_remove(mlxsw_sp, base_port + i * offset); 20348c2ecf20Sopenharmony_ci 20358c2ecf20Sopenharmony_ci mlxsw_sp_port_unsplit_create(mlxsw_sp, base_port, count, offset); 20368c2ecf20Sopenharmony_ci 20378c2ecf20Sopenharmony_ci return 0; 20388c2ecf20Sopenharmony_ci} 20398c2ecf20Sopenharmony_ci 20408c2ecf20Sopenharmony_cistatic void 20418c2ecf20Sopenharmony_cimlxsw_sp_port_down_wipe_counters(struct mlxsw_sp_port *mlxsw_sp_port) 20428c2ecf20Sopenharmony_ci{ 20438c2ecf20Sopenharmony_ci int i; 20448c2ecf20Sopenharmony_ci 20458c2ecf20Sopenharmony_ci for (i = 0; i < TC_MAX_QUEUE; i++) 20468c2ecf20Sopenharmony_ci mlxsw_sp_port->periodic_hw_stats.xstats.backlog[i] = 0; 20478c2ecf20Sopenharmony_ci} 20488c2ecf20Sopenharmony_ci 20498c2ecf20Sopenharmony_cistatic void mlxsw_sp_pude_event_func(const struct mlxsw_reg_info *reg, 20508c2ecf20Sopenharmony_ci char *pude_pl, void *priv) 20518c2ecf20Sopenharmony_ci{ 20528c2ecf20Sopenharmony_ci struct mlxsw_sp *mlxsw_sp = priv; 20538c2ecf20Sopenharmony_ci struct mlxsw_sp_port *mlxsw_sp_port; 20548c2ecf20Sopenharmony_ci enum mlxsw_reg_pude_oper_status status; 20558c2ecf20Sopenharmony_ci unsigned int max_ports; 20568c2ecf20Sopenharmony_ci u8 local_port; 20578c2ecf20Sopenharmony_ci 20588c2ecf20Sopenharmony_ci max_ports = mlxsw_core_max_ports(mlxsw_sp->core); 20598c2ecf20Sopenharmony_ci local_port = mlxsw_reg_pude_local_port_get(pude_pl); 20608c2ecf20Sopenharmony_ci 20618c2ecf20Sopenharmony_ci if (WARN_ON_ONCE(!local_port || local_port >= max_ports)) 20628c2ecf20Sopenharmony_ci return; 20638c2ecf20Sopenharmony_ci mlxsw_sp_port = mlxsw_sp->ports[local_port]; 20648c2ecf20Sopenharmony_ci if (!mlxsw_sp_port) 20658c2ecf20Sopenharmony_ci return; 20668c2ecf20Sopenharmony_ci 20678c2ecf20Sopenharmony_ci status = mlxsw_reg_pude_oper_status_get(pude_pl); 20688c2ecf20Sopenharmony_ci if (status == MLXSW_PORT_OPER_STATUS_UP) { 20698c2ecf20Sopenharmony_ci netdev_info(mlxsw_sp_port->dev, "link up\n"); 20708c2ecf20Sopenharmony_ci netif_carrier_on(mlxsw_sp_port->dev); 20718c2ecf20Sopenharmony_ci mlxsw_core_schedule_dw(&mlxsw_sp_port->ptp.shaper_dw, 0); 20728c2ecf20Sopenharmony_ci } else { 20738c2ecf20Sopenharmony_ci netdev_info(mlxsw_sp_port->dev, "link down\n"); 20748c2ecf20Sopenharmony_ci netif_carrier_off(mlxsw_sp_port->dev); 20758c2ecf20Sopenharmony_ci mlxsw_sp_port_down_wipe_counters(mlxsw_sp_port); 20768c2ecf20Sopenharmony_ci } 20778c2ecf20Sopenharmony_ci} 20788c2ecf20Sopenharmony_ci 20798c2ecf20Sopenharmony_cistatic void mlxsw_sp1_ptp_fifo_event_func(struct mlxsw_sp *mlxsw_sp, 20808c2ecf20Sopenharmony_ci char *mtpptr_pl, bool ingress) 20818c2ecf20Sopenharmony_ci{ 20828c2ecf20Sopenharmony_ci u8 local_port; 20838c2ecf20Sopenharmony_ci u8 num_rec; 20848c2ecf20Sopenharmony_ci int i; 20858c2ecf20Sopenharmony_ci 20868c2ecf20Sopenharmony_ci local_port = mlxsw_reg_mtpptr_local_port_get(mtpptr_pl); 20878c2ecf20Sopenharmony_ci num_rec = mlxsw_reg_mtpptr_num_rec_get(mtpptr_pl); 20888c2ecf20Sopenharmony_ci for (i = 0; i < num_rec; i++) { 20898c2ecf20Sopenharmony_ci u8 domain_number; 20908c2ecf20Sopenharmony_ci u8 message_type; 20918c2ecf20Sopenharmony_ci u16 sequence_id; 20928c2ecf20Sopenharmony_ci u64 timestamp; 20938c2ecf20Sopenharmony_ci 20948c2ecf20Sopenharmony_ci mlxsw_reg_mtpptr_unpack(mtpptr_pl, i, &message_type, 20958c2ecf20Sopenharmony_ci &domain_number, &sequence_id, 20968c2ecf20Sopenharmony_ci ×tamp); 20978c2ecf20Sopenharmony_ci mlxsw_sp1_ptp_got_timestamp(mlxsw_sp, ingress, local_port, 20988c2ecf20Sopenharmony_ci message_type, domain_number, 20998c2ecf20Sopenharmony_ci sequence_id, timestamp); 21008c2ecf20Sopenharmony_ci } 21018c2ecf20Sopenharmony_ci} 21028c2ecf20Sopenharmony_ci 21038c2ecf20Sopenharmony_cistatic void mlxsw_sp1_ptp_ing_fifo_event_func(const struct mlxsw_reg_info *reg, 21048c2ecf20Sopenharmony_ci char *mtpptr_pl, void *priv) 21058c2ecf20Sopenharmony_ci{ 21068c2ecf20Sopenharmony_ci struct mlxsw_sp *mlxsw_sp = priv; 21078c2ecf20Sopenharmony_ci 21088c2ecf20Sopenharmony_ci mlxsw_sp1_ptp_fifo_event_func(mlxsw_sp, mtpptr_pl, true); 21098c2ecf20Sopenharmony_ci} 21108c2ecf20Sopenharmony_ci 21118c2ecf20Sopenharmony_cistatic void mlxsw_sp1_ptp_egr_fifo_event_func(const struct mlxsw_reg_info *reg, 21128c2ecf20Sopenharmony_ci char *mtpptr_pl, void *priv) 21138c2ecf20Sopenharmony_ci{ 21148c2ecf20Sopenharmony_ci struct mlxsw_sp *mlxsw_sp = priv; 21158c2ecf20Sopenharmony_ci 21168c2ecf20Sopenharmony_ci mlxsw_sp1_ptp_fifo_event_func(mlxsw_sp, mtpptr_pl, false); 21178c2ecf20Sopenharmony_ci} 21188c2ecf20Sopenharmony_ci 21198c2ecf20Sopenharmony_civoid mlxsw_sp_rx_listener_no_mark_func(struct sk_buff *skb, 21208c2ecf20Sopenharmony_ci u8 local_port, void *priv) 21218c2ecf20Sopenharmony_ci{ 21228c2ecf20Sopenharmony_ci struct mlxsw_sp *mlxsw_sp = priv; 21238c2ecf20Sopenharmony_ci struct mlxsw_sp_port *mlxsw_sp_port = mlxsw_sp->ports[local_port]; 21248c2ecf20Sopenharmony_ci struct mlxsw_sp_port_pcpu_stats *pcpu_stats; 21258c2ecf20Sopenharmony_ci 21268c2ecf20Sopenharmony_ci if (unlikely(!mlxsw_sp_port)) { 21278c2ecf20Sopenharmony_ci dev_warn_ratelimited(mlxsw_sp->bus_info->dev, "Port %d: skb received for non-existent port\n", 21288c2ecf20Sopenharmony_ci local_port); 21298c2ecf20Sopenharmony_ci return; 21308c2ecf20Sopenharmony_ci } 21318c2ecf20Sopenharmony_ci 21328c2ecf20Sopenharmony_ci skb->dev = mlxsw_sp_port->dev; 21338c2ecf20Sopenharmony_ci 21348c2ecf20Sopenharmony_ci pcpu_stats = this_cpu_ptr(mlxsw_sp_port->pcpu_stats); 21358c2ecf20Sopenharmony_ci u64_stats_update_begin(&pcpu_stats->syncp); 21368c2ecf20Sopenharmony_ci pcpu_stats->rx_packets++; 21378c2ecf20Sopenharmony_ci pcpu_stats->rx_bytes += skb->len; 21388c2ecf20Sopenharmony_ci u64_stats_update_end(&pcpu_stats->syncp); 21398c2ecf20Sopenharmony_ci 21408c2ecf20Sopenharmony_ci skb->protocol = eth_type_trans(skb, skb->dev); 21418c2ecf20Sopenharmony_ci netif_receive_skb(skb); 21428c2ecf20Sopenharmony_ci} 21438c2ecf20Sopenharmony_ci 21448c2ecf20Sopenharmony_cistatic void mlxsw_sp_rx_listener_mark_func(struct sk_buff *skb, u8 local_port, 21458c2ecf20Sopenharmony_ci void *priv) 21468c2ecf20Sopenharmony_ci{ 21478c2ecf20Sopenharmony_ci skb->offload_fwd_mark = 1; 21488c2ecf20Sopenharmony_ci return mlxsw_sp_rx_listener_no_mark_func(skb, local_port, priv); 21498c2ecf20Sopenharmony_ci} 21508c2ecf20Sopenharmony_ci 21518c2ecf20Sopenharmony_cistatic void mlxsw_sp_rx_listener_l3_mark_func(struct sk_buff *skb, 21528c2ecf20Sopenharmony_ci u8 local_port, void *priv) 21538c2ecf20Sopenharmony_ci{ 21548c2ecf20Sopenharmony_ci skb->offload_l3_fwd_mark = 1; 21558c2ecf20Sopenharmony_ci skb->offload_fwd_mark = 1; 21568c2ecf20Sopenharmony_ci return mlxsw_sp_rx_listener_no_mark_func(skb, local_port, priv); 21578c2ecf20Sopenharmony_ci} 21588c2ecf20Sopenharmony_ci 21598c2ecf20Sopenharmony_civoid mlxsw_sp_ptp_receive(struct mlxsw_sp *mlxsw_sp, struct sk_buff *skb, 21608c2ecf20Sopenharmony_ci u8 local_port) 21618c2ecf20Sopenharmony_ci{ 21628c2ecf20Sopenharmony_ci mlxsw_sp->ptp_ops->receive(mlxsw_sp, skb, local_port); 21638c2ecf20Sopenharmony_ci} 21648c2ecf20Sopenharmony_ci 21658c2ecf20Sopenharmony_civoid mlxsw_sp_sample_receive(struct mlxsw_sp *mlxsw_sp, struct sk_buff *skb, 21668c2ecf20Sopenharmony_ci u8 local_port) 21678c2ecf20Sopenharmony_ci{ 21688c2ecf20Sopenharmony_ci struct mlxsw_sp_port *mlxsw_sp_port = mlxsw_sp->ports[local_port]; 21698c2ecf20Sopenharmony_ci struct mlxsw_sp_port_sample *sample; 21708c2ecf20Sopenharmony_ci u32 size; 21718c2ecf20Sopenharmony_ci 21728c2ecf20Sopenharmony_ci if (unlikely(!mlxsw_sp_port)) { 21738c2ecf20Sopenharmony_ci dev_warn_ratelimited(mlxsw_sp->bus_info->dev, "Port %d: sample skb received for non-existent port\n", 21748c2ecf20Sopenharmony_ci local_port); 21758c2ecf20Sopenharmony_ci goto out; 21768c2ecf20Sopenharmony_ci } 21778c2ecf20Sopenharmony_ci 21788c2ecf20Sopenharmony_ci rcu_read_lock(); 21798c2ecf20Sopenharmony_ci sample = rcu_dereference(mlxsw_sp_port->sample); 21808c2ecf20Sopenharmony_ci if (!sample) 21818c2ecf20Sopenharmony_ci goto out_unlock; 21828c2ecf20Sopenharmony_ci size = sample->truncate ? sample->trunc_size : skb->len; 21838c2ecf20Sopenharmony_ci psample_sample_packet(sample->psample_group, skb, size, 21848c2ecf20Sopenharmony_ci mlxsw_sp_port->dev->ifindex, 0, sample->rate); 21858c2ecf20Sopenharmony_ciout_unlock: 21868c2ecf20Sopenharmony_ci rcu_read_unlock(); 21878c2ecf20Sopenharmony_ciout: 21888c2ecf20Sopenharmony_ci consume_skb(skb); 21898c2ecf20Sopenharmony_ci} 21908c2ecf20Sopenharmony_ci 21918c2ecf20Sopenharmony_ci#define MLXSW_SP_RXL_NO_MARK(_trap_id, _action, _trap_group, _is_ctrl) \ 21928c2ecf20Sopenharmony_ci MLXSW_RXL(mlxsw_sp_rx_listener_no_mark_func, _trap_id, _action, \ 21938c2ecf20Sopenharmony_ci _is_ctrl, SP_##_trap_group, DISCARD) 21948c2ecf20Sopenharmony_ci 21958c2ecf20Sopenharmony_ci#define MLXSW_SP_RXL_MARK(_trap_id, _action, _trap_group, _is_ctrl) \ 21968c2ecf20Sopenharmony_ci MLXSW_RXL(mlxsw_sp_rx_listener_mark_func, _trap_id, _action, \ 21978c2ecf20Sopenharmony_ci _is_ctrl, SP_##_trap_group, DISCARD) 21988c2ecf20Sopenharmony_ci 21998c2ecf20Sopenharmony_ci#define MLXSW_SP_RXL_L3_MARK(_trap_id, _action, _trap_group, _is_ctrl) \ 22008c2ecf20Sopenharmony_ci MLXSW_RXL(mlxsw_sp_rx_listener_l3_mark_func, _trap_id, _action, \ 22018c2ecf20Sopenharmony_ci _is_ctrl, SP_##_trap_group, DISCARD) 22028c2ecf20Sopenharmony_ci 22038c2ecf20Sopenharmony_ci#define MLXSW_SP_EVENTL(_func, _trap_id) \ 22048c2ecf20Sopenharmony_ci MLXSW_EVENTL(_func, _trap_id, SP_EVENT) 22058c2ecf20Sopenharmony_ci 22068c2ecf20Sopenharmony_cistatic const struct mlxsw_listener mlxsw_sp_listener[] = { 22078c2ecf20Sopenharmony_ci /* Events */ 22088c2ecf20Sopenharmony_ci MLXSW_SP_EVENTL(mlxsw_sp_pude_event_func, PUDE), 22098c2ecf20Sopenharmony_ci /* L2 traps */ 22108c2ecf20Sopenharmony_ci MLXSW_SP_RXL_NO_MARK(FID_MISS, TRAP_TO_CPU, FID_MISS, false), 22118c2ecf20Sopenharmony_ci /* L3 traps */ 22128c2ecf20Sopenharmony_ci MLXSW_SP_RXL_MARK(IPV6_UNSPECIFIED_ADDRESS, TRAP_TO_CPU, ROUTER_EXP, 22138c2ecf20Sopenharmony_ci false), 22148c2ecf20Sopenharmony_ci MLXSW_SP_RXL_MARK(IPV6_LINK_LOCAL_SRC, TRAP_TO_CPU, ROUTER_EXP, false), 22158c2ecf20Sopenharmony_ci MLXSW_SP_RXL_MARK(IPV6_MC_LINK_LOCAL_DEST, TRAP_TO_CPU, ROUTER_EXP, 22168c2ecf20Sopenharmony_ci false), 22178c2ecf20Sopenharmony_ci MLXSW_SP_RXL_NO_MARK(DISCARD_ING_ROUTER_SIP_CLASS_E, FORWARD, 22188c2ecf20Sopenharmony_ci ROUTER_EXP, false), 22198c2ecf20Sopenharmony_ci MLXSW_SP_RXL_NO_MARK(DISCARD_ING_ROUTER_MC_DMAC, FORWARD, 22208c2ecf20Sopenharmony_ci ROUTER_EXP, false), 22218c2ecf20Sopenharmony_ci MLXSW_SP_RXL_NO_MARK(DISCARD_ING_ROUTER_SIP_DIP, FORWARD, 22228c2ecf20Sopenharmony_ci ROUTER_EXP, false), 22238c2ecf20Sopenharmony_ci MLXSW_SP_RXL_NO_MARK(DISCARD_ING_ROUTER_DIP_LINK_LOCAL, FORWARD, 22248c2ecf20Sopenharmony_ci ROUTER_EXP, false), 22258c2ecf20Sopenharmony_ci /* Multicast Router Traps */ 22268c2ecf20Sopenharmony_ci MLXSW_SP_RXL_MARK(ACL1, TRAP_TO_CPU, MULTICAST, false), 22278c2ecf20Sopenharmony_ci MLXSW_SP_RXL_L3_MARK(ACL2, TRAP_TO_CPU, MULTICAST, false), 22288c2ecf20Sopenharmony_ci /* NVE traps */ 22298c2ecf20Sopenharmony_ci MLXSW_SP_RXL_MARK(NVE_ENCAP_ARP, TRAP_TO_CPU, NEIGH_DISCOVERY, false), 22308c2ecf20Sopenharmony_ci}; 22318c2ecf20Sopenharmony_ci 22328c2ecf20Sopenharmony_cistatic const struct mlxsw_listener mlxsw_sp1_listener[] = { 22338c2ecf20Sopenharmony_ci /* Events */ 22348c2ecf20Sopenharmony_ci MLXSW_EVENTL(mlxsw_sp1_ptp_egr_fifo_event_func, PTP_EGR_FIFO, SP_PTP0), 22358c2ecf20Sopenharmony_ci MLXSW_EVENTL(mlxsw_sp1_ptp_ing_fifo_event_func, PTP_ING_FIFO, SP_PTP0), 22368c2ecf20Sopenharmony_ci}; 22378c2ecf20Sopenharmony_ci 22388c2ecf20Sopenharmony_cistatic int mlxsw_sp_cpu_policers_set(struct mlxsw_core *mlxsw_core) 22398c2ecf20Sopenharmony_ci{ 22408c2ecf20Sopenharmony_ci struct mlxsw_sp *mlxsw_sp = mlxsw_core_driver_priv(mlxsw_core); 22418c2ecf20Sopenharmony_ci char qpcr_pl[MLXSW_REG_QPCR_LEN]; 22428c2ecf20Sopenharmony_ci enum mlxsw_reg_qpcr_ir_units ir_units; 22438c2ecf20Sopenharmony_ci int max_cpu_policers; 22448c2ecf20Sopenharmony_ci bool is_bytes; 22458c2ecf20Sopenharmony_ci u8 burst_size; 22468c2ecf20Sopenharmony_ci u32 rate; 22478c2ecf20Sopenharmony_ci int i, err; 22488c2ecf20Sopenharmony_ci 22498c2ecf20Sopenharmony_ci if (!MLXSW_CORE_RES_VALID(mlxsw_core, MAX_CPU_POLICERS)) 22508c2ecf20Sopenharmony_ci return -EIO; 22518c2ecf20Sopenharmony_ci 22528c2ecf20Sopenharmony_ci max_cpu_policers = MLXSW_CORE_RES_GET(mlxsw_core, MAX_CPU_POLICERS); 22538c2ecf20Sopenharmony_ci 22548c2ecf20Sopenharmony_ci ir_units = MLXSW_REG_QPCR_IR_UNITS_M; 22558c2ecf20Sopenharmony_ci for (i = 0; i < max_cpu_policers; i++) { 22568c2ecf20Sopenharmony_ci is_bytes = false; 22578c2ecf20Sopenharmony_ci switch (i) { 22588c2ecf20Sopenharmony_ci case MLXSW_REG_HTGT_TRAP_GROUP_SP_ROUTER_EXP: 22598c2ecf20Sopenharmony_ci case MLXSW_REG_HTGT_TRAP_GROUP_SP_MULTICAST: 22608c2ecf20Sopenharmony_ci case MLXSW_REG_HTGT_TRAP_GROUP_SP_FID_MISS: 22618c2ecf20Sopenharmony_ci rate = 1024; 22628c2ecf20Sopenharmony_ci burst_size = 7; 22638c2ecf20Sopenharmony_ci break; 22648c2ecf20Sopenharmony_ci default: 22658c2ecf20Sopenharmony_ci continue; 22668c2ecf20Sopenharmony_ci } 22678c2ecf20Sopenharmony_ci 22688c2ecf20Sopenharmony_ci __set_bit(i, mlxsw_sp->trap->policers_usage); 22698c2ecf20Sopenharmony_ci mlxsw_reg_qpcr_pack(qpcr_pl, i, ir_units, is_bytes, rate, 22708c2ecf20Sopenharmony_ci burst_size); 22718c2ecf20Sopenharmony_ci err = mlxsw_reg_write(mlxsw_core, MLXSW_REG(qpcr), qpcr_pl); 22728c2ecf20Sopenharmony_ci if (err) 22738c2ecf20Sopenharmony_ci return err; 22748c2ecf20Sopenharmony_ci } 22758c2ecf20Sopenharmony_ci 22768c2ecf20Sopenharmony_ci return 0; 22778c2ecf20Sopenharmony_ci} 22788c2ecf20Sopenharmony_ci 22798c2ecf20Sopenharmony_cistatic int mlxsw_sp_trap_groups_set(struct mlxsw_core *mlxsw_core) 22808c2ecf20Sopenharmony_ci{ 22818c2ecf20Sopenharmony_ci char htgt_pl[MLXSW_REG_HTGT_LEN]; 22828c2ecf20Sopenharmony_ci enum mlxsw_reg_htgt_trap_group i; 22838c2ecf20Sopenharmony_ci int max_cpu_policers; 22848c2ecf20Sopenharmony_ci int max_trap_groups; 22858c2ecf20Sopenharmony_ci u8 priority, tc; 22868c2ecf20Sopenharmony_ci u16 policer_id; 22878c2ecf20Sopenharmony_ci int err; 22888c2ecf20Sopenharmony_ci 22898c2ecf20Sopenharmony_ci if (!MLXSW_CORE_RES_VALID(mlxsw_core, MAX_TRAP_GROUPS)) 22908c2ecf20Sopenharmony_ci return -EIO; 22918c2ecf20Sopenharmony_ci 22928c2ecf20Sopenharmony_ci max_trap_groups = MLXSW_CORE_RES_GET(mlxsw_core, MAX_TRAP_GROUPS); 22938c2ecf20Sopenharmony_ci max_cpu_policers = MLXSW_CORE_RES_GET(mlxsw_core, MAX_CPU_POLICERS); 22948c2ecf20Sopenharmony_ci 22958c2ecf20Sopenharmony_ci for (i = 0; i < max_trap_groups; i++) { 22968c2ecf20Sopenharmony_ci policer_id = i; 22978c2ecf20Sopenharmony_ci switch (i) { 22988c2ecf20Sopenharmony_ci case MLXSW_REG_HTGT_TRAP_GROUP_SP_ROUTER_EXP: 22998c2ecf20Sopenharmony_ci case MLXSW_REG_HTGT_TRAP_GROUP_SP_MULTICAST: 23008c2ecf20Sopenharmony_ci case MLXSW_REG_HTGT_TRAP_GROUP_SP_FID_MISS: 23018c2ecf20Sopenharmony_ci priority = 1; 23028c2ecf20Sopenharmony_ci tc = 1; 23038c2ecf20Sopenharmony_ci break; 23048c2ecf20Sopenharmony_ci case MLXSW_REG_HTGT_TRAP_GROUP_SP_EVENT: 23058c2ecf20Sopenharmony_ci priority = MLXSW_REG_HTGT_DEFAULT_PRIORITY; 23068c2ecf20Sopenharmony_ci tc = MLXSW_REG_HTGT_DEFAULT_TC; 23078c2ecf20Sopenharmony_ci policer_id = MLXSW_REG_HTGT_INVALID_POLICER; 23088c2ecf20Sopenharmony_ci break; 23098c2ecf20Sopenharmony_ci default: 23108c2ecf20Sopenharmony_ci continue; 23118c2ecf20Sopenharmony_ci } 23128c2ecf20Sopenharmony_ci 23138c2ecf20Sopenharmony_ci if (max_cpu_policers <= policer_id && 23148c2ecf20Sopenharmony_ci policer_id != MLXSW_REG_HTGT_INVALID_POLICER) 23158c2ecf20Sopenharmony_ci return -EIO; 23168c2ecf20Sopenharmony_ci 23178c2ecf20Sopenharmony_ci mlxsw_reg_htgt_pack(htgt_pl, i, policer_id, priority, tc); 23188c2ecf20Sopenharmony_ci err = mlxsw_reg_write(mlxsw_core, MLXSW_REG(htgt), htgt_pl); 23198c2ecf20Sopenharmony_ci if (err) 23208c2ecf20Sopenharmony_ci return err; 23218c2ecf20Sopenharmony_ci } 23228c2ecf20Sopenharmony_ci 23238c2ecf20Sopenharmony_ci return 0; 23248c2ecf20Sopenharmony_ci} 23258c2ecf20Sopenharmony_ci 23268c2ecf20Sopenharmony_cistatic int mlxsw_sp_traps_register(struct mlxsw_sp *mlxsw_sp, 23278c2ecf20Sopenharmony_ci const struct mlxsw_listener listeners[], 23288c2ecf20Sopenharmony_ci size_t listeners_count) 23298c2ecf20Sopenharmony_ci{ 23308c2ecf20Sopenharmony_ci int i; 23318c2ecf20Sopenharmony_ci int err; 23328c2ecf20Sopenharmony_ci 23338c2ecf20Sopenharmony_ci for (i = 0; i < listeners_count; i++) { 23348c2ecf20Sopenharmony_ci err = mlxsw_core_trap_register(mlxsw_sp->core, 23358c2ecf20Sopenharmony_ci &listeners[i], 23368c2ecf20Sopenharmony_ci mlxsw_sp); 23378c2ecf20Sopenharmony_ci if (err) 23388c2ecf20Sopenharmony_ci goto err_listener_register; 23398c2ecf20Sopenharmony_ci 23408c2ecf20Sopenharmony_ci } 23418c2ecf20Sopenharmony_ci return 0; 23428c2ecf20Sopenharmony_ci 23438c2ecf20Sopenharmony_cierr_listener_register: 23448c2ecf20Sopenharmony_ci for (i--; i >= 0; i--) { 23458c2ecf20Sopenharmony_ci mlxsw_core_trap_unregister(mlxsw_sp->core, 23468c2ecf20Sopenharmony_ci &listeners[i], 23478c2ecf20Sopenharmony_ci mlxsw_sp); 23488c2ecf20Sopenharmony_ci } 23498c2ecf20Sopenharmony_ci return err; 23508c2ecf20Sopenharmony_ci} 23518c2ecf20Sopenharmony_ci 23528c2ecf20Sopenharmony_cistatic void mlxsw_sp_traps_unregister(struct mlxsw_sp *mlxsw_sp, 23538c2ecf20Sopenharmony_ci const struct mlxsw_listener listeners[], 23548c2ecf20Sopenharmony_ci size_t listeners_count) 23558c2ecf20Sopenharmony_ci{ 23568c2ecf20Sopenharmony_ci int i; 23578c2ecf20Sopenharmony_ci 23588c2ecf20Sopenharmony_ci for (i = 0; i < listeners_count; i++) { 23598c2ecf20Sopenharmony_ci mlxsw_core_trap_unregister(mlxsw_sp->core, 23608c2ecf20Sopenharmony_ci &listeners[i], 23618c2ecf20Sopenharmony_ci mlxsw_sp); 23628c2ecf20Sopenharmony_ci } 23638c2ecf20Sopenharmony_ci} 23648c2ecf20Sopenharmony_ci 23658c2ecf20Sopenharmony_cistatic int mlxsw_sp_traps_init(struct mlxsw_sp *mlxsw_sp) 23668c2ecf20Sopenharmony_ci{ 23678c2ecf20Sopenharmony_ci struct mlxsw_sp_trap *trap; 23688c2ecf20Sopenharmony_ci u64 max_policers; 23698c2ecf20Sopenharmony_ci int err; 23708c2ecf20Sopenharmony_ci 23718c2ecf20Sopenharmony_ci if (!MLXSW_CORE_RES_VALID(mlxsw_sp->core, MAX_CPU_POLICERS)) 23728c2ecf20Sopenharmony_ci return -EIO; 23738c2ecf20Sopenharmony_ci max_policers = MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_CPU_POLICERS); 23748c2ecf20Sopenharmony_ci trap = kzalloc(struct_size(trap, policers_usage, 23758c2ecf20Sopenharmony_ci BITS_TO_LONGS(max_policers)), GFP_KERNEL); 23768c2ecf20Sopenharmony_ci if (!trap) 23778c2ecf20Sopenharmony_ci return -ENOMEM; 23788c2ecf20Sopenharmony_ci trap->max_policers = max_policers; 23798c2ecf20Sopenharmony_ci mlxsw_sp->trap = trap; 23808c2ecf20Sopenharmony_ci 23818c2ecf20Sopenharmony_ci err = mlxsw_sp_cpu_policers_set(mlxsw_sp->core); 23828c2ecf20Sopenharmony_ci if (err) 23838c2ecf20Sopenharmony_ci goto err_cpu_policers_set; 23848c2ecf20Sopenharmony_ci 23858c2ecf20Sopenharmony_ci err = mlxsw_sp_trap_groups_set(mlxsw_sp->core); 23868c2ecf20Sopenharmony_ci if (err) 23878c2ecf20Sopenharmony_ci goto err_trap_groups_set; 23888c2ecf20Sopenharmony_ci 23898c2ecf20Sopenharmony_ci err = mlxsw_sp_traps_register(mlxsw_sp, mlxsw_sp_listener, 23908c2ecf20Sopenharmony_ci ARRAY_SIZE(mlxsw_sp_listener)); 23918c2ecf20Sopenharmony_ci if (err) 23928c2ecf20Sopenharmony_ci goto err_traps_register; 23938c2ecf20Sopenharmony_ci 23948c2ecf20Sopenharmony_ci err = mlxsw_sp_traps_register(mlxsw_sp, mlxsw_sp->listeners, 23958c2ecf20Sopenharmony_ci mlxsw_sp->listeners_count); 23968c2ecf20Sopenharmony_ci if (err) 23978c2ecf20Sopenharmony_ci goto err_extra_traps_init; 23988c2ecf20Sopenharmony_ci 23998c2ecf20Sopenharmony_ci return 0; 24008c2ecf20Sopenharmony_ci 24018c2ecf20Sopenharmony_cierr_extra_traps_init: 24028c2ecf20Sopenharmony_ci mlxsw_sp_traps_unregister(mlxsw_sp, mlxsw_sp_listener, 24038c2ecf20Sopenharmony_ci ARRAY_SIZE(mlxsw_sp_listener)); 24048c2ecf20Sopenharmony_cierr_traps_register: 24058c2ecf20Sopenharmony_cierr_trap_groups_set: 24068c2ecf20Sopenharmony_cierr_cpu_policers_set: 24078c2ecf20Sopenharmony_ci kfree(trap); 24088c2ecf20Sopenharmony_ci return err; 24098c2ecf20Sopenharmony_ci} 24108c2ecf20Sopenharmony_ci 24118c2ecf20Sopenharmony_cistatic void mlxsw_sp_traps_fini(struct mlxsw_sp *mlxsw_sp) 24128c2ecf20Sopenharmony_ci{ 24138c2ecf20Sopenharmony_ci mlxsw_sp_traps_unregister(mlxsw_sp, mlxsw_sp->listeners, 24148c2ecf20Sopenharmony_ci mlxsw_sp->listeners_count); 24158c2ecf20Sopenharmony_ci mlxsw_sp_traps_unregister(mlxsw_sp, mlxsw_sp_listener, 24168c2ecf20Sopenharmony_ci ARRAY_SIZE(mlxsw_sp_listener)); 24178c2ecf20Sopenharmony_ci kfree(mlxsw_sp->trap); 24188c2ecf20Sopenharmony_ci} 24198c2ecf20Sopenharmony_ci 24208c2ecf20Sopenharmony_ci#define MLXSW_SP_LAG_SEED_INIT 0xcafecafe 24218c2ecf20Sopenharmony_ci 24228c2ecf20Sopenharmony_cistatic int mlxsw_sp_lag_init(struct mlxsw_sp *mlxsw_sp) 24238c2ecf20Sopenharmony_ci{ 24248c2ecf20Sopenharmony_ci char slcr_pl[MLXSW_REG_SLCR_LEN]; 24258c2ecf20Sopenharmony_ci u32 seed; 24268c2ecf20Sopenharmony_ci int err; 24278c2ecf20Sopenharmony_ci 24288c2ecf20Sopenharmony_ci seed = jhash(mlxsw_sp->base_mac, sizeof(mlxsw_sp->base_mac), 24298c2ecf20Sopenharmony_ci MLXSW_SP_LAG_SEED_INIT); 24308c2ecf20Sopenharmony_ci mlxsw_reg_slcr_pack(slcr_pl, MLXSW_REG_SLCR_LAG_HASH_SMAC | 24318c2ecf20Sopenharmony_ci MLXSW_REG_SLCR_LAG_HASH_DMAC | 24328c2ecf20Sopenharmony_ci MLXSW_REG_SLCR_LAG_HASH_ETHERTYPE | 24338c2ecf20Sopenharmony_ci MLXSW_REG_SLCR_LAG_HASH_VLANID | 24348c2ecf20Sopenharmony_ci MLXSW_REG_SLCR_LAG_HASH_SIP | 24358c2ecf20Sopenharmony_ci MLXSW_REG_SLCR_LAG_HASH_DIP | 24368c2ecf20Sopenharmony_ci MLXSW_REG_SLCR_LAG_HASH_SPORT | 24378c2ecf20Sopenharmony_ci MLXSW_REG_SLCR_LAG_HASH_DPORT | 24388c2ecf20Sopenharmony_ci MLXSW_REG_SLCR_LAG_HASH_IPPROTO, seed); 24398c2ecf20Sopenharmony_ci err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(slcr), slcr_pl); 24408c2ecf20Sopenharmony_ci if (err) 24418c2ecf20Sopenharmony_ci return err; 24428c2ecf20Sopenharmony_ci 24438c2ecf20Sopenharmony_ci if (!MLXSW_CORE_RES_VALID(mlxsw_sp->core, MAX_LAG) || 24448c2ecf20Sopenharmony_ci !MLXSW_CORE_RES_VALID(mlxsw_sp->core, MAX_LAG_MEMBERS)) 24458c2ecf20Sopenharmony_ci return -EIO; 24468c2ecf20Sopenharmony_ci 24478c2ecf20Sopenharmony_ci mlxsw_sp->lags = kcalloc(MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_LAG), 24488c2ecf20Sopenharmony_ci sizeof(struct mlxsw_sp_upper), 24498c2ecf20Sopenharmony_ci GFP_KERNEL); 24508c2ecf20Sopenharmony_ci if (!mlxsw_sp->lags) 24518c2ecf20Sopenharmony_ci return -ENOMEM; 24528c2ecf20Sopenharmony_ci 24538c2ecf20Sopenharmony_ci return 0; 24548c2ecf20Sopenharmony_ci} 24558c2ecf20Sopenharmony_ci 24568c2ecf20Sopenharmony_cistatic void mlxsw_sp_lag_fini(struct mlxsw_sp *mlxsw_sp) 24578c2ecf20Sopenharmony_ci{ 24588c2ecf20Sopenharmony_ci kfree(mlxsw_sp->lags); 24598c2ecf20Sopenharmony_ci} 24608c2ecf20Sopenharmony_ci 24618c2ecf20Sopenharmony_cistatic int mlxsw_sp_basic_trap_groups_set(struct mlxsw_core *mlxsw_core) 24628c2ecf20Sopenharmony_ci{ 24638c2ecf20Sopenharmony_ci char htgt_pl[MLXSW_REG_HTGT_LEN]; 24648c2ecf20Sopenharmony_ci int err; 24658c2ecf20Sopenharmony_ci 24668c2ecf20Sopenharmony_ci mlxsw_reg_htgt_pack(htgt_pl, MLXSW_REG_HTGT_TRAP_GROUP_EMAD, 24678c2ecf20Sopenharmony_ci MLXSW_REG_HTGT_INVALID_POLICER, 24688c2ecf20Sopenharmony_ci MLXSW_REG_HTGT_DEFAULT_PRIORITY, 24698c2ecf20Sopenharmony_ci MLXSW_REG_HTGT_DEFAULT_TC); 24708c2ecf20Sopenharmony_ci err = mlxsw_reg_write(mlxsw_core, MLXSW_REG(htgt), htgt_pl); 24718c2ecf20Sopenharmony_ci if (err) 24728c2ecf20Sopenharmony_ci return err; 24738c2ecf20Sopenharmony_ci 24748c2ecf20Sopenharmony_ci mlxsw_reg_htgt_pack(htgt_pl, MLXSW_REG_HTGT_TRAP_GROUP_MFDE, 24758c2ecf20Sopenharmony_ci MLXSW_REG_HTGT_INVALID_POLICER, 24768c2ecf20Sopenharmony_ci MLXSW_REG_HTGT_DEFAULT_PRIORITY, 24778c2ecf20Sopenharmony_ci MLXSW_REG_HTGT_DEFAULT_TC); 24788c2ecf20Sopenharmony_ci err = mlxsw_reg_write(mlxsw_core, MLXSW_REG(htgt), htgt_pl); 24798c2ecf20Sopenharmony_ci if (err) 24808c2ecf20Sopenharmony_ci return err; 24818c2ecf20Sopenharmony_ci 24828c2ecf20Sopenharmony_ci mlxsw_reg_htgt_pack(htgt_pl, MLXSW_REG_HTGT_TRAP_GROUP_MTWE, 24838c2ecf20Sopenharmony_ci MLXSW_REG_HTGT_INVALID_POLICER, 24848c2ecf20Sopenharmony_ci MLXSW_REG_HTGT_DEFAULT_PRIORITY, 24858c2ecf20Sopenharmony_ci MLXSW_REG_HTGT_DEFAULT_TC); 24868c2ecf20Sopenharmony_ci err = mlxsw_reg_write(mlxsw_core, MLXSW_REG(htgt), htgt_pl); 24878c2ecf20Sopenharmony_ci if (err) 24888c2ecf20Sopenharmony_ci return err; 24898c2ecf20Sopenharmony_ci 24908c2ecf20Sopenharmony_ci mlxsw_reg_htgt_pack(htgt_pl, MLXSW_REG_HTGT_TRAP_GROUP_PMPE, 24918c2ecf20Sopenharmony_ci MLXSW_REG_HTGT_INVALID_POLICER, 24928c2ecf20Sopenharmony_ci MLXSW_REG_HTGT_DEFAULT_PRIORITY, 24938c2ecf20Sopenharmony_ci MLXSW_REG_HTGT_DEFAULT_TC); 24948c2ecf20Sopenharmony_ci return mlxsw_reg_write(mlxsw_core, MLXSW_REG(htgt), htgt_pl); 24958c2ecf20Sopenharmony_ci} 24968c2ecf20Sopenharmony_ci 24978c2ecf20Sopenharmony_cistatic const struct mlxsw_sp_ptp_ops mlxsw_sp1_ptp_ops = { 24988c2ecf20Sopenharmony_ci .clock_init = mlxsw_sp1_ptp_clock_init, 24998c2ecf20Sopenharmony_ci .clock_fini = mlxsw_sp1_ptp_clock_fini, 25008c2ecf20Sopenharmony_ci .init = mlxsw_sp1_ptp_init, 25018c2ecf20Sopenharmony_ci .fini = mlxsw_sp1_ptp_fini, 25028c2ecf20Sopenharmony_ci .receive = mlxsw_sp1_ptp_receive, 25038c2ecf20Sopenharmony_ci .transmitted = mlxsw_sp1_ptp_transmitted, 25048c2ecf20Sopenharmony_ci .hwtstamp_get = mlxsw_sp1_ptp_hwtstamp_get, 25058c2ecf20Sopenharmony_ci .hwtstamp_set = mlxsw_sp1_ptp_hwtstamp_set, 25068c2ecf20Sopenharmony_ci .shaper_work = mlxsw_sp1_ptp_shaper_work, 25078c2ecf20Sopenharmony_ci .get_ts_info = mlxsw_sp1_ptp_get_ts_info, 25088c2ecf20Sopenharmony_ci .get_stats_count = mlxsw_sp1_get_stats_count, 25098c2ecf20Sopenharmony_ci .get_stats_strings = mlxsw_sp1_get_stats_strings, 25108c2ecf20Sopenharmony_ci .get_stats = mlxsw_sp1_get_stats, 25118c2ecf20Sopenharmony_ci}; 25128c2ecf20Sopenharmony_ci 25138c2ecf20Sopenharmony_cistatic const struct mlxsw_sp_ptp_ops mlxsw_sp2_ptp_ops = { 25148c2ecf20Sopenharmony_ci .clock_init = mlxsw_sp2_ptp_clock_init, 25158c2ecf20Sopenharmony_ci .clock_fini = mlxsw_sp2_ptp_clock_fini, 25168c2ecf20Sopenharmony_ci .init = mlxsw_sp2_ptp_init, 25178c2ecf20Sopenharmony_ci .fini = mlxsw_sp2_ptp_fini, 25188c2ecf20Sopenharmony_ci .receive = mlxsw_sp2_ptp_receive, 25198c2ecf20Sopenharmony_ci .transmitted = mlxsw_sp2_ptp_transmitted, 25208c2ecf20Sopenharmony_ci .hwtstamp_get = mlxsw_sp2_ptp_hwtstamp_get, 25218c2ecf20Sopenharmony_ci .hwtstamp_set = mlxsw_sp2_ptp_hwtstamp_set, 25228c2ecf20Sopenharmony_ci .shaper_work = mlxsw_sp2_ptp_shaper_work, 25238c2ecf20Sopenharmony_ci .get_ts_info = mlxsw_sp2_ptp_get_ts_info, 25248c2ecf20Sopenharmony_ci .get_stats_count = mlxsw_sp2_get_stats_count, 25258c2ecf20Sopenharmony_ci .get_stats_strings = mlxsw_sp2_get_stats_strings, 25268c2ecf20Sopenharmony_ci .get_stats = mlxsw_sp2_get_stats, 25278c2ecf20Sopenharmony_ci}; 25288c2ecf20Sopenharmony_ci 25298c2ecf20Sopenharmony_cistatic int mlxsw_sp_netdevice_event(struct notifier_block *unused, 25308c2ecf20Sopenharmony_ci unsigned long event, void *ptr); 25318c2ecf20Sopenharmony_ci 25328c2ecf20Sopenharmony_cistatic int mlxsw_sp_init(struct mlxsw_core *mlxsw_core, 25338c2ecf20Sopenharmony_ci const struct mlxsw_bus_info *mlxsw_bus_info, 25348c2ecf20Sopenharmony_ci struct netlink_ext_ack *extack) 25358c2ecf20Sopenharmony_ci{ 25368c2ecf20Sopenharmony_ci struct mlxsw_sp *mlxsw_sp = mlxsw_core_driver_priv(mlxsw_core); 25378c2ecf20Sopenharmony_ci int err; 25388c2ecf20Sopenharmony_ci 25398c2ecf20Sopenharmony_ci mlxsw_sp->core = mlxsw_core; 25408c2ecf20Sopenharmony_ci mlxsw_sp->bus_info = mlxsw_bus_info; 25418c2ecf20Sopenharmony_ci 25428c2ecf20Sopenharmony_ci mlxsw_core_emad_string_tlv_enable(mlxsw_core); 25438c2ecf20Sopenharmony_ci 25448c2ecf20Sopenharmony_ci err = mlxsw_sp_base_mac_get(mlxsw_sp); 25458c2ecf20Sopenharmony_ci if (err) { 25468c2ecf20Sopenharmony_ci dev_err(mlxsw_sp->bus_info->dev, "Failed to get base mac\n"); 25478c2ecf20Sopenharmony_ci return err; 25488c2ecf20Sopenharmony_ci } 25498c2ecf20Sopenharmony_ci 25508c2ecf20Sopenharmony_ci err = mlxsw_sp_kvdl_init(mlxsw_sp); 25518c2ecf20Sopenharmony_ci if (err) { 25528c2ecf20Sopenharmony_ci dev_err(mlxsw_sp->bus_info->dev, "Failed to initialize KVDL\n"); 25538c2ecf20Sopenharmony_ci return err; 25548c2ecf20Sopenharmony_ci } 25558c2ecf20Sopenharmony_ci 25568c2ecf20Sopenharmony_ci err = mlxsw_sp_fids_init(mlxsw_sp); 25578c2ecf20Sopenharmony_ci if (err) { 25588c2ecf20Sopenharmony_ci dev_err(mlxsw_sp->bus_info->dev, "Failed to initialize FIDs\n"); 25598c2ecf20Sopenharmony_ci goto err_fids_init; 25608c2ecf20Sopenharmony_ci } 25618c2ecf20Sopenharmony_ci 25628c2ecf20Sopenharmony_ci err = mlxsw_sp_policers_init(mlxsw_sp); 25638c2ecf20Sopenharmony_ci if (err) { 25648c2ecf20Sopenharmony_ci dev_err(mlxsw_sp->bus_info->dev, "Failed to initialize policers\n"); 25658c2ecf20Sopenharmony_ci goto err_policers_init; 25668c2ecf20Sopenharmony_ci } 25678c2ecf20Sopenharmony_ci 25688c2ecf20Sopenharmony_ci err = mlxsw_sp_traps_init(mlxsw_sp); 25698c2ecf20Sopenharmony_ci if (err) { 25708c2ecf20Sopenharmony_ci dev_err(mlxsw_sp->bus_info->dev, "Failed to set traps\n"); 25718c2ecf20Sopenharmony_ci goto err_traps_init; 25728c2ecf20Sopenharmony_ci } 25738c2ecf20Sopenharmony_ci 25748c2ecf20Sopenharmony_ci err = mlxsw_sp_devlink_traps_init(mlxsw_sp); 25758c2ecf20Sopenharmony_ci if (err) { 25768c2ecf20Sopenharmony_ci dev_err(mlxsw_sp->bus_info->dev, "Failed to initialize devlink traps\n"); 25778c2ecf20Sopenharmony_ci goto err_devlink_traps_init; 25788c2ecf20Sopenharmony_ci } 25798c2ecf20Sopenharmony_ci 25808c2ecf20Sopenharmony_ci err = mlxsw_sp_buffers_init(mlxsw_sp); 25818c2ecf20Sopenharmony_ci if (err) { 25828c2ecf20Sopenharmony_ci dev_err(mlxsw_sp->bus_info->dev, "Failed to initialize buffers\n"); 25838c2ecf20Sopenharmony_ci goto err_buffers_init; 25848c2ecf20Sopenharmony_ci } 25858c2ecf20Sopenharmony_ci 25868c2ecf20Sopenharmony_ci err = mlxsw_sp_lag_init(mlxsw_sp); 25878c2ecf20Sopenharmony_ci if (err) { 25888c2ecf20Sopenharmony_ci dev_err(mlxsw_sp->bus_info->dev, "Failed to initialize LAG\n"); 25898c2ecf20Sopenharmony_ci goto err_lag_init; 25908c2ecf20Sopenharmony_ci } 25918c2ecf20Sopenharmony_ci 25928c2ecf20Sopenharmony_ci /* Initialize SPAN before router and switchdev, so that those components 25938c2ecf20Sopenharmony_ci * can call mlxsw_sp_span_respin(). 25948c2ecf20Sopenharmony_ci */ 25958c2ecf20Sopenharmony_ci err = mlxsw_sp_span_init(mlxsw_sp); 25968c2ecf20Sopenharmony_ci if (err) { 25978c2ecf20Sopenharmony_ci dev_err(mlxsw_sp->bus_info->dev, "Failed to init span system\n"); 25988c2ecf20Sopenharmony_ci goto err_span_init; 25998c2ecf20Sopenharmony_ci } 26008c2ecf20Sopenharmony_ci 26018c2ecf20Sopenharmony_ci err = mlxsw_sp_switchdev_init(mlxsw_sp); 26028c2ecf20Sopenharmony_ci if (err) { 26038c2ecf20Sopenharmony_ci dev_err(mlxsw_sp->bus_info->dev, "Failed to initialize switchdev\n"); 26048c2ecf20Sopenharmony_ci goto err_switchdev_init; 26058c2ecf20Sopenharmony_ci } 26068c2ecf20Sopenharmony_ci 26078c2ecf20Sopenharmony_ci err = mlxsw_sp_counter_pool_init(mlxsw_sp); 26088c2ecf20Sopenharmony_ci if (err) { 26098c2ecf20Sopenharmony_ci dev_err(mlxsw_sp->bus_info->dev, "Failed to init counter pool\n"); 26108c2ecf20Sopenharmony_ci goto err_counter_pool_init; 26118c2ecf20Sopenharmony_ci } 26128c2ecf20Sopenharmony_ci 26138c2ecf20Sopenharmony_ci err = mlxsw_sp_afa_init(mlxsw_sp); 26148c2ecf20Sopenharmony_ci if (err) { 26158c2ecf20Sopenharmony_ci dev_err(mlxsw_sp->bus_info->dev, "Failed to initialize ACL actions\n"); 26168c2ecf20Sopenharmony_ci goto err_afa_init; 26178c2ecf20Sopenharmony_ci } 26188c2ecf20Sopenharmony_ci 26198c2ecf20Sopenharmony_ci err = mlxsw_sp_nve_init(mlxsw_sp); 26208c2ecf20Sopenharmony_ci if (err) { 26218c2ecf20Sopenharmony_ci dev_err(mlxsw_sp->bus_info->dev, "Failed to initialize NVE\n"); 26228c2ecf20Sopenharmony_ci goto err_nve_init; 26238c2ecf20Sopenharmony_ci } 26248c2ecf20Sopenharmony_ci 26258c2ecf20Sopenharmony_ci err = mlxsw_sp_acl_init(mlxsw_sp); 26268c2ecf20Sopenharmony_ci if (err) { 26278c2ecf20Sopenharmony_ci dev_err(mlxsw_sp->bus_info->dev, "Failed to initialize ACL\n"); 26288c2ecf20Sopenharmony_ci goto err_acl_init; 26298c2ecf20Sopenharmony_ci } 26308c2ecf20Sopenharmony_ci 26318c2ecf20Sopenharmony_ci err = mlxsw_sp_router_init(mlxsw_sp, extack); 26328c2ecf20Sopenharmony_ci if (err) { 26338c2ecf20Sopenharmony_ci dev_err(mlxsw_sp->bus_info->dev, "Failed to initialize router\n"); 26348c2ecf20Sopenharmony_ci goto err_router_init; 26358c2ecf20Sopenharmony_ci } 26368c2ecf20Sopenharmony_ci 26378c2ecf20Sopenharmony_ci if (mlxsw_sp->bus_info->read_frc_capable) { 26388c2ecf20Sopenharmony_ci /* NULL is a valid return value from clock_init */ 26398c2ecf20Sopenharmony_ci mlxsw_sp->clock = 26408c2ecf20Sopenharmony_ci mlxsw_sp->ptp_ops->clock_init(mlxsw_sp, 26418c2ecf20Sopenharmony_ci mlxsw_sp->bus_info->dev); 26428c2ecf20Sopenharmony_ci if (IS_ERR(mlxsw_sp->clock)) { 26438c2ecf20Sopenharmony_ci err = PTR_ERR(mlxsw_sp->clock); 26448c2ecf20Sopenharmony_ci dev_err(mlxsw_sp->bus_info->dev, "Failed to init ptp clock\n"); 26458c2ecf20Sopenharmony_ci goto err_ptp_clock_init; 26468c2ecf20Sopenharmony_ci } 26478c2ecf20Sopenharmony_ci } 26488c2ecf20Sopenharmony_ci 26498c2ecf20Sopenharmony_ci if (mlxsw_sp->clock) { 26508c2ecf20Sopenharmony_ci /* NULL is a valid return value from ptp_ops->init */ 26518c2ecf20Sopenharmony_ci mlxsw_sp->ptp_state = mlxsw_sp->ptp_ops->init(mlxsw_sp); 26528c2ecf20Sopenharmony_ci if (IS_ERR(mlxsw_sp->ptp_state)) { 26538c2ecf20Sopenharmony_ci err = PTR_ERR(mlxsw_sp->ptp_state); 26548c2ecf20Sopenharmony_ci dev_err(mlxsw_sp->bus_info->dev, "Failed to initialize PTP\n"); 26558c2ecf20Sopenharmony_ci goto err_ptp_init; 26568c2ecf20Sopenharmony_ci } 26578c2ecf20Sopenharmony_ci } 26588c2ecf20Sopenharmony_ci 26598c2ecf20Sopenharmony_ci /* Initialize netdevice notifier after router and SPAN is initialized, 26608c2ecf20Sopenharmony_ci * so that the event handler can use router structures and call SPAN 26618c2ecf20Sopenharmony_ci * respin. 26628c2ecf20Sopenharmony_ci */ 26638c2ecf20Sopenharmony_ci mlxsw_sp->netdevice_nb.notifier_call = mlxsw_sp_netdevice_event; 26648c2ecf20Sopenharmony_ci err = register_netdevice_notifier_net(mlxsw_sp_net(mlxsw_sp), 26658c2ecf20Sopenharmony_ci &mlxsw_sp->netdevice_nb); 26668c2ecf20Sopenharmony_ci if (err) { 26678c2ecf20Sopenharmony_ci dev_err(mlxsw_sp->bus_info->dev, "Failed to register netdev notifier\n"); 26688c2ecf20Sopenharmony_ci goto err_netdev_notifier; 26698c2ecf20Sopenharmony_ci } 26708c2ecf20Sopenharmony_ci 26718c2ecf20Sopenharmony_ci err = mlxsw_sp_dpipe_init(mlxsw_sp); 26728c2ecf20Sopenharmony_ci if (err) { 26738c2ecf20Sopenharmony_ci dev_err(mlxsw_sp->bus_info->dev, "Failed to init pipeline debug\n"); 26748c2ecf20Sopenharmony_ci goto err_dpipe_init; 26758c2ecf20Sopenharmony_ci } 26768c2ecf20Sopenharmony_ci 26778c2ecf20Sopenharmony_ci err = mlxsw_sp_port_module_info_init(mlxsw_sp); 26788c2ecf20Sopenharmony_ci if (err) { 26798c2ecf20Sopenharmony_ci dev_err(mlxsw_sp->bus_info->dev, "Failed to init port module info\n"); 26808c2ecf20Sopenharmony_ci goto err_port_module_info_init; 26818c2ecf20Sopenharmony_ci } 26828c2ecf20Sopenharmony_ci 26838c2ecf20Sopenharmony_ci err = mlxsw_sp_ports_create(mlxsw_sp); 26848c2ecf20Sopenharmony_ci if (err) { 26858c2ecf20Sopenharmony_ci dev_err(mlxsw_sp->bus_info->dev, "Failed to create ports\n"); 26868c2ecf20Sopenharmony_ci goto err_ports_create; 26878c2ecf20Sopenharmony_ci } 26888c2ecf20Sopenharmony_ci 26898c2ecf20Sopenharmony_ci return 0; 26908c2ecf20Sopenharmony_ci 26918c2ecf20Sopenharmony_cierr_ports_create: 26928c2ecf20Sopenharmony_ci mlxsw_sp_port_module_info_fini(mlxsw_sp); 26938c2ecf20Sopenharmony_cierr_port_module_info_init: 26948c2ecf20Sopenharmony_ci mlxsw_sp_dpipe_fini(mlxsw_sp); 26958c2ecf20Sopenharmony_cierr_dpipe_init: 26968c2ecf20Sopenharmony_ci unregister_netdevice_notifier_net(mlxsw_sp_net(mlxsw_sp), 26978c2ecf20Sopenharmony_ci &mlxsw_sp->netdevice_nb); 26988c2ecf20Sopenharmony_cierr_netdev_notifier: 26998c2ecf20Sopenharmony_ci if (mlxsw_sp->clock) 27008c2ecf20Sopenharmony_ci mlxsw_sp->ptp_ops->fini(mlxsw_sp->ptp_state); 27018c2ecf20Sopenharmony_cierr_ptp_init: 27028c2ecf20Sopenharmony_ci if (mlxsw_sp->clock) 27038c2ecf20Sopenharmony_ci mlxsw_sp->ptp_ops->clock_fini(mlxsw_sp->clock); 27048c2ecf20Sopenharmony_cierr_ptp_clock_init: 27058c2ecf20Sopenharmony_ci mlxsw_sp_router_fini(mlxsw_sp); 27068c2ecf20Sopenharmony_cierr_router_init: 27078c2ecf20Sopenharmony_ci mlxsw_sp_acl_fini(mlxsw_sp); 27088c2ecf20Sopenharmony_cierr_acl_init: 27098c2ecf20Sopenharmony_ci mlxsw_sp_nve_fini(mlxsw_sp); 27108c2ecf20Sopenharmony_cierr_nve_init: 27118c2ecf20Sopenharmony_ci mlxsw_sp_afa_fini(mlxsw_sp); 27128c2ecf20Sopenharmony_cierr_afa_init: 27138c2ecf20Sopenharmony_ci mlxsw_sp_counter_pool_fini(mlxsw_sp); 27148c2ecf20Sopenharmony_cierr_counter_pool_init: 27158c2ecf20Sopenharmony_ci mlxsw_sp_switchdev_fini(mlxsw_sp); 27168c2ecf20Sopenharmony_cierr_switchdev_init: 27178c2ecf20Sopenharmony_ci mlxsw_sp_span_fini(mlxsw_sp); 27188c2ecf20Sopenharmony_cierr_span_init: 27198c2ecf20Sopenharmony_ci mlxsw_sp_lag_fini(mlxsw_sp); 27208c2ecf20Sopenharmony_cierr_lag_init: 27218c2ecf20Sopenharmony_ci mlxsw_sp_buffers_fini(mlxsw_sp); 27228c2ecf20Sopenharmony_cierr_buffers_init: 27238c2ecf20Sopenharmony_ci mlxsw_sp_devlink_traps_fini(mlxsw_sp); 27248c2ecf20Sopenharmony_cierr_devlink_traps_init: 27258c2ecf20Sopenharmony_ci mlxsw_sp_traps_fini(mlxsw_sp); 27268c2ecf20Sopenharmony_cierr_traps_init: 27278c2ecf20Sopenharmony_ci mlxsw_sp_policers_fini(mlxsw_sp); 27288c2ecf20Sopenharmony_cierr_policers_init: 27298c2ecf20Sopenharmony_ci mlxsw_sp_fids_fini(mlxsw_sp); 27308c2ecf20Sopenharmony_cierr_fids_init: 27318c2ecf20Sopenharmony_ci mlxsw_sp_kvdl_fini(mlxsw_sp); 27328c2ecf20Sopenharmony_ci return err; 27338c2ecf20Sopenharmony_ci} 27348c2ecf20Sopenharmony_ci 27358c2ecf20Sopenharmony_cistatic int mlxsw_sp1_init(struct mlxsw_core *mlxsw_core, 27368c2ecf20Sopenharmony_ci const struct mlxsw_bus_info *mlxsw_bus_info, 27378c2ecf20Sopenharmony_ci struct netlink_ext_ack *extack) 27388c2ecf20Sopenharmony_ci{ 27398c2ecf20Sopenharmony_ci struct mlxsw_sp *mlxsw_sp = mlxsw_core_driver_priv(mlxsw_core); 27408c2ecf20Sopenharmony_ci 27418c2ecf20Sopenharmony_ci mlxsw_sp->kvdl_ops = &mlxsw_sp1_kvdl_ops; 27428c2ecf20Sopenharmony_ci mlxsw_sp->afa_ops = &mlxsw_sp1_act_afa_ops; 27438c2ecf20Sopenharmony_ci mlxsw_sp->afk_ops = &mlxsw_sp1_afk_ops; 27448c2ecf20Sopenharmony_ci mlxsw_sp->mr_tcam_ops = &mlxsw_sp1_mr_tcam_ops; 27458c2ecf20Sopenharmony_ci mlxsw_sp->acl_rulei_ops = &mlxsw_sp1_acl_rulei_ops; 27468c2ecf20Sopenharmony_ci mlxsw_sp->acl_tcam_ops = &mlxsw_sp1_acl_tcam_ops; 27478c2ecf20Sopenharmony_ci mlxsw_sp->nve_ops_arr = mlxsw_sp1_nve_ops_arr; 27488c2ecf20Sopenharmony_ci mlxsw_sp->mac_mask = mlxsw_sp1_mac_mask; 27498c2ecf20Sopenharmony_ci mlxsw_sp->rif_ops_arr = mlxsw_sp1_rif_ops_arr; 27508c2ecf20Sopenharmony_ci mlxsw_sp->sb_vals = &mlxsw_sp1_sb_vals; 27518c2ecf20Sopenharmony_ci mlxsw_sp->sb_ops = &mlxsw_sp1_sb_ops; 27528c2ecf20Sopenharmony_ci mlxsw_sp->port_type_speed_ops = &mlxsw_sp1_port_type_speed_ops; 27538c2ecf20Sopenharmony_ci mlxsw_sp->ptp_ops = &mlxsw_sp1_ptp_ops; 27548c2ecf20Sopenharmony_ci mlxsw_sp->span_ops = &mlxsw_sp1_span_ops; 27558c2ecf20Sopenharmony_ci mlxsw_sp->policer_core_ops = &mlxsw_sp1_policer_core_ops; 27568c2ecf20Sopenharmony_ci mlxsw_sp->trap_ops = &mlxsw_sp1_trap_ops; 27578c2ecf20Sopenharmony_ci mlxsw_sp->listeners = mlxsw_sp1_listener; 27588c2ecf20Sopenharmony_ci mlxsw_sp->listeners_count = ARRAY_SIZE(mlxsw_sp1_listener); 27598c2ecf20Sopenharmony_ci mlxsw_sp->lowest_shaper_bs = MLXSW_REG_QEEC_LOWEST_SHAPER_BS_SP1; 27608c2ecf20Sopenharmony_ci 27618c2ecf20Sopenharmony_ci return mlxsw_sp_init(mlxsw_core, mlxsw_bus_info, extack); 27628c2ecf20Sopenharmony_ci} 27638c2ecf20Sopenharmony_ci 27648c2ecf20Sopenharmony_cistatic int mlxsw_sp2_init(struct mlxsw_core *mlxsw_core, 27658c2ecf20Sopenharmony_ci const struct mlxsw_bus_info *mlxsw_bus_info, 27668c2ecf20Sopenharmony_ci struct netlink_ext_ack *extack) 27678c2ecf20Sopenharmony_ci{ 27688c2ecf20Sopenharmony_ci struct mlxsw_sp *mlxsw_sp = mlxsw_core_driver_priv(mlxsw_core); 27698c2ecf20Sopenharmony_ci 27708c2ecf20Sopenharmony_ci mlxsw_sp->kvdl_ops = &mlxsw_sp2_kvdl_ops; 27718c2ecf20Sopenharmony_ci mlxsw_sp->afa_ops = &mlxsw_sp2_act_afa_ops; 27728c2ecf20Sopenharmony_ci mlxsw_sp->afk_ops = &mlxsw_sp2_afk_ops; 27738c2ecf20Sopenharmony_ci mlxsw_sp->mr_tcam_ops = &mlxsw_sp2_mr_tcam_ops; 27748c2ecf20Sopenharmony_ci mlxsw_sp->acl_rulei_ops = &mlxsw_sp2_acl_rulei_ops; 27758c2ecf20Sopenharmony_ci mlxsw_sp->acl_tcam_ops = &mlxsw_sp2_acl_tcam_ops; 27768c2ecf20Sopenharmony_ci mlxsw_sp->nve_ops_arr = mlxsw_sp2_nve_ops_arr; 27778c2ecf20Sopenharmony_ci mlxsw_sp->mac_mask = mlxsw_sp2_mac_mask; 27788c2ecf20Sopenharmony_ci mlxsw_sp->rif_ops_arr = mlxsw_sp2_rif_ops_arr; 27798c2ecf20Sopenharmony_ci mlxsw_sp->sb_vals = &mlxsw_sp2_sb_vals; 27808c2ecf20Sopenharmony_ci mlxsw_sp->sb_ops = &mlxsw_sp2_sb_ops; 27818c2ecf20Sopenharmony_ci mlxsw_sp->port_type_speed_ops = &mlxsw_sp2_port_type_speed_ops; 27828c2ecf20Sopenharmony_ci mlxsw_sp->ptp_ops = &mlxsw_sp2_ptp_ops; 27838c2ecf20Sopenharmony_ci mlxsw_sp->span_ops = &mlxsw_sp2_span_ops; 27848c2ecf20Sopenharmony_ci mlxsw_sp->policer_core_ops = &mlxsw_sp2_policer_core_ops; 27858c2ecf20Sopenharmony_ci mlxsw_sp->trap_ops = &mlxsw_sp2_trap_ops; 27868c2ecf20Sopenharmony_ci mlxsw_sp->lowest_shaper_bs = MLXSW_REG_QEEC_LOWEST_SHAPER_BS_SP2; 27878c2ecf20Sopenharmony_ci 27888c2ecf20Sopenharmony_ci return mlxsw_sp_init(mlxsw_core, mlxsw_bus_info, extack); 27898c2ecf20Sopenharmony_ci} 27908c2ecf20Sopenharmony_ci 27918c2ecf20Sopenharmony_cistatic int mlxsw_sp3_init(struct mlxsw_core *mlxsw_core, 27928c2ecf20Sopenharmony_ci const struct mlxsw_bus_info *mlxsw_bus_info, 27938c2ecf20Sopenharmony_ci struct netlink_ext_ack *extack) 27948c2ecf20Sopenharmony_ci{ 27958c2ecf20Sopenharmony_ci struct mlxsw_sp *mlxsw_sp = mlxsw_core_driver_priv(mlxsw_core); 27968c2ecf20Sopenharmony_ci 27978c2ecf20Sopenharmony_ci mlxsw_sp->kvdl_ops = &mlxsw_sp2_kvdl_ops; 27988c2ecf20Sopenharmony_ci mlxsw_sp->afa_ops = &mlxsw_sp2_act_afa_ops; 27998c2ecf20Sopenharmony_ci mlxsw_sp->afk_ops = &mlxsw_sp2_afk_ops; 28008c2ecf20Sopenharmony_ci mlxsw_sp->mr_tcam_ops = &mlxsw_sp2_mr_tcam_ops; 28018c2ecf20Sopenharmony_ci mlxsw_sp->acl_rulei_ops = &mlxsw_sp2_acl_rulei_ops; 28028c2ecf20Sopenharmony_ci mlxsw_sp->acl_tcam_ops = &mlxsw_sp2_acl_tcam_ops; 28038c2ecf20Sopenharmony_ci mlxsw_sp->nve_ops_arr = mlxsw_sp2_nve_ops_arr; 28048c2ecf20Sopenharmony_ci mlxsw_sp->mac_mask = mlxsw_sp2_mac_mask; 28058c2ecf20Sopenharmony_ci mlxsw_sp->rif_ops_arr = mlxsw_sp2_rif_ops_arr; 28068c2ecf20Sopenharmony_ci mlxsw_sp->sb_vals = &mlxsw_sp2_sb_vals; 28078c2ecf20Sopenharmony_ci mlxsw_sp->sb_ops = &mlxsw_sp3_sb_ops; 28088c2ecf20Sopenharmony_ci mlxsw_sp->port_type_speed_ops = &mlxsw_sp2_port_type_speed_ops; 28098c2ecf20Sopenharmony_ci mlxsw_sp->ptp_ops = &mlxsw_sp2_ptp_ops; 28108c2ecf20Sopenharmony_ci mlxsw_sp->span_ops = &mlxsw_sp3_span_ops; 28118c2ecf20Sopenharmony_ci mlxsw_sp->policer_core_ops = &mlxsw_sp2_policer_core_ops; 28128c2ecf20Sopenharmony_ci mlxsw_sp->trap_ops = &mlxsw_sp2_trap_ops; 28138c2ecf20Sopenharmony_ci mlxsw_sp->lowest_shaper_bs = MLXSW_REG_QEEC_LOWEST_SHAPER_BS_SP3; 28148c2ecf20Sopenharmony_ci 28158c2ecf20Sopenharmony_ci return mlxsw_sp_init(mlxsw_core, mlxsw_bus_info, extack); 28168c2ecf20Sopenharmony_ci} 28178c2ecf20Sopenharmony_ci 28188c2ecf20Sopenharmony_cistatic void mlxsw_sp_fini(struct mlxsw_core *mlxsw_core) 28198c2ecf20Sopenharmony_ci{ 28208c2ecf20Sopenharmony_ci struct mlxsw_sp *mlxsw_sp = mlxsw_core_driver_priv(mlxsw_core); 28218c2ecf20Sopenharmony_ci 28228c2ecf20Sopenharmony_ci mlxsw_sp_ports_remove(mlxsw_sp); 28238c2ecf20Sopenharmony_ci mlxsw_sp_port_module_info_fini(mlxsw_sp); 28248c2ecf20Sopenharmony_ci mlxsw_sp_dpipe_fini(mlxsw_sp); 28258c2ecf20Sopenharmony_ci unregister_netdevice_notifier_net(mlxsw_sp_net(mlxsw_sp), 28268c2ecf20Sopenharmony_ci &mlxsw_sp->netdevice_nb); 28278c2ecf20Sopenharmony_ci if (mlxsw_sp->clock) { 28288c2ecf20Sopenharmony_ci mlxsw_sp->ptp_ops->fini(mlxsw_sp->ptp_state); 28298c2ecf20Sopenharmony_ci mlxsw_sp->ptp_ops->clock_fini(mlxsw_sp->clock); 28308c2ecf20Sopenharmony_ci } 28318c2ecf20Sopenharmony_ci mlxsw_sp_router_fini(mlxsw_sp); 28328c2ecf20Sopenharmony_ci mlxsw_sp_acl_fini(mlxsw_sp); 28338c2ecf20Sopenharmony_ci mlxsw_sp_nve_fini(mlxsw_sp); 28348c2ecf20Sopenharmony_ci mlxsw_sp_afa_fini(mlxsw_sp); 28358c2ecf20Sopenharmony_ci mlxsw_sp_counter_pool_fini(mlxsw_sp); 28368c2ecf20Sopenharmony_ci mlxsw_sp_switchdev_fini(mlxsw_sp); 28378c2ecf20Sopenharmony_ci mlxsw_sp_span_fini(mlxsw_sp); 28388c2ecf20Sopenharmony_ci mlxsw_sp_lag_fini(mlxsw_sp); 28398c2ecf20Sopenharmony_ci mlxsw_sp_buffers_fini(mlxsw_sp); 28408c2ecf20Sopenharmony_ci mlxsw_sp_devlink_traps_fini(mlxsw_sp); 28418c2ecf20Sopenharmony_ci mlxsw_sp_traps_fini(mlxsw_sp); 28428c2ecf20Sopenharmony_ci mlxsw_sp_policers_fini(mlxsw_sp); 28438c2ecf20Sopenharmony_ci mlxsw_sp_fids_fini(mlxsw_sp); 28448c2ecf20Sopenharmony_ci mlxsw_sp_kvdl_fini(mlxsw_sp); 28458c2ecf20Sopenharmony_ci} 28468c2ecf20Sopenharmony_ci 28478c2ecf20Sopenharmony_ci/* Per-FID flood tables are used for both "true" 802.1D FIDs and emulated 28488c2ecf20Sopenharmony_ci * 802.1Q FIDs 28498c2ecf20Sopenharmony_ci */ 28508c2ecf20Sopenharmony_ci#define MLXSW_SP_FID_FLOOD_TABLE_SIZE (MLXSW_SP_FID_8021D_MAX + \ 28518c2ecf20Sopenharmony_ci VLAN_VID_MASK - 1) 28528c2ecf20Sopenharmony_ci 28538c2ecf20Sopenharmony_cistatic const struct mlxsw_config_profile mlxsw_sp1_config_profile = { 28548c2ecf20Sopenharmony_ci .used_max_mid = 1, 28558c2ecf20Sopenharmony_ci .max_mid = MLXSW_SP_MID_MAX, 28568c2ecf20Sopenharmony_ci .used_flood_tables = 1, 28578c2ecf20Sopenharmony_ci .used_flood_mode = 1, 28588c2ecf20Sopenharmony_ci .flood_mode = 3, 28598c2ecf20Sopenharmony_ci .max_fid_flood_tables = 3, 28608c2ecf20Sopenharmony_ci .fid_flood_table_size = MLXSW_SP_FID_FLOOD_TABLE_SIZE, 28618c2ecf20Sopenharmony_ci .used_max_ib_mc = 1, 28628c2ecf20Sopenharmony_ci .max_ib_mc = 0, 28638c2ecf20Sopenharmony_ci .used_max_pkey = 1, 28648c2ecf20Sopenharmony_ci .max_pkey = 0, 28658c2ecf20Sopenharmony_ci .used_kvd_sizes = 1, 28668c2ecf20Sopenharmony_ci .kvd_hash_single_parts = 59, 28678c2ecf20Sopenharmony_ci .kvd_hash_double_parts = 41, 28688c2ecf20Sopenharmony_ci .kvd_linear_size = MLXSW_SP_KVD_LINEAR_SIZE, 28698c2ecf20Sopenharmony_ci .swid_config = { 28708c2ecf20Sopenharmony_ci { 28718c2ecf20Sopenharmony_ci .used_type = 1, 28728c2ecf20Sopenharmony_ci .type = MLXSW_PORT_SWID_TYPE_ETH, 28738c2ecf20Sopenharmony_ci } 28748c2ecf20Sopenharmony_ci }, 28758c2ecf20Sopenharmony_ci}; 28768c2ecf20Sopenharmony_ci 28778c2ecf20Sopenharmony_cistatic const struct mlxsw_config_profile mlxsw_sp2_config_profile = { 28788c2ecf20Sopenharmony_ci .used_max_mid = 1, 28798c2ecf20Sopenharmony_ci .max_mid = MLXSW_SP_MID_MAX, 28808c2ecf20Sopenharmony_ci .used_flood_tables = 1, 28818c2ecf20Sopenharmony_ci .used_flood_mode = 1, 28828c2ecf20Sopenharmony_ci .flood_mode = 3, 28838c2ecf20Sopenharmony_ci .max_fid_flood_tables = 3, 28848c2ecf20Sopenharmony_ci .fid_flood_table_size = MLXSW_SP_FID_FLOOD_TABLE_SIZE, 28858c2ecf20Sopenharmony_ci .used_max_ib_mc = 1, 28868c2ecf20Sopenharmony_ci .max_ib_mc = 0, 28878c2ecf20Sopenharmony_ci .used_max_pkey = 1, 28888c2ecf20Sopenharmony_ci .max_pkey = 0, 28898c2ecf20Sopenharmony_ci .swid_config = { 28908c2ecf20Sopenharmony_ci { 28918c2ecf20Sopenharmony_ci .used_type = 1, 28928c2ecf20Sopenharmony_ci .type = MLXSW_PORT_SWID_TYPE_ETH, 28938c2ecf20Sopenharmony_ci } 28948c2ecf20Sopenharmony_ci }, 28958c2ecf20Sopenharmony_ci}; 28968c2ecf20Sopenharmony_ci 28978c2ecf20Sopenharmony_cistatic void 28988c2ecf20Sopenharmony_cimlxsw_sp_resource_size_params_prepare(struct mlxsw_core *mlxsw_core, 28998c2ecf20Sopenharmony_ci struct devlink_resource_size_params *kvd_size_params, 29008c2ecf20Sopenharmony_ci struct devlink_resource_size_params *linear_size_params, 29018c2ecf20Sopenharmony_ci struct devlink_resource_size_params *hash_double_size_params, 29028c2ecf20Sopenharmony_ci struct devlink_resource_size_params *hash_single_size_params) 29038c2ecf20Sopenharmony_ci{ 29048c2ecf20Sopenharmony_ci u32 single_size_min = MLXSW_CORE_RES_GET(mlxsw_core, 29058c2ecf20Sopenharmony_ci KVD_SINGLE_MIN_SIZE); 29068c2ecf20Sopenharmony_ci u32 double_size_min = MLXSW_CORE_RES_GET(mlxsw_core, 29078c2ecf20Sopenharmony_ci KVD_DOUBLE_MIN_SIZE); 29088c2ecf20Sopenharmony_ci u32 kvd_size = MLXSW_CORE_RES_GET(mlxsw_core, KVD_SIZE); 29098c2ecf20Sopenharmony_ci u32 linear_size_min = 0; 29108c2ecf20Sopenharmony_ci 29118c2ecf20Sopenharmony_ci devlink_resource_size_params_init(kvd_size_params, kvd_size, kvd_size, 29128c2ecf20Sopenharmony_ci MLXSW_SP_KVD_GRANULARITY, 29138c2ecf20Sopenharmony_ci DEVLINK_RESOURCE_UNIT_ENTRY); 29148c2ecf20Sopenharmony_ci devlink_resource_size_params_init(linear_size_params, linear_size_min, 29158c2ecf20Sopenharmony_ci kvd_size - single_size_min - 29168c2ecf20Sopenharmony_ci double_size_min, 29178c2ecf20Sopenharmony_ci MLXSW_SP_KVD_GRANULARITY, 29188c2ecf20Sopenharmony_ci DEVLINK_RESOURCE_UNIT_ENTRY); 29198c2ecf20Sopenharmony_ci devlink_resource_size_params_init(hash_double_size_params, 29208c2ecf20Sopenharmony_ci double_size_min, 29218c2ecf20Sopenharmony_ci kvd_size - single_size_min - 29228c2ecf20Sopenharmony_ci linear_size_min, 29238c2ecf20Sopenharmony_ci MLXSW_SP_KVD_GRANULARITY, 29248c2ecf20Sopenharmony_ci DEVLINK_RESOURCE_UNIT_ENTRY); 29258c2ecf20Sopenharmony_ci devlink_resource_size_params_init(hash_single_size_params, 29268c2ecf20Sopenharmony_ci single_size_min, 29278c2ecf20Sopenharmony_ci kvd_size - double_size_min - 29288c2ecf20Sopenharmony_ci linear_size_min, 29298c2ecf20Sopenharmony_ci MLXSW_SP_KVD_GRANULARITY, 29308c2ecf20Sopenharmony_ci DEVLINK_RESOURCE_UNIT_ENTRY); 29318c2ecf20Sopenharmony_ci} 29328c2ecf20Sopenharmony_ci 29338c2ecf20Sopenharmony_cistatic int mlxsw_sp1_resources_kvd_register(struct mlxsw_core *mlxsw_core) 29348c2ecf20Sopenharmony_ci{ 29358c2ecf20Sopenharmony_ci struct devlink *devlink = priv_to_devlink(mlxsw_core); 29368c2ecf20Sopenharmony_ci struct devlink_resource_size_params hash_single_size_params; 29378c2ecf20Sopenharmony_ci struct devlink_resource_size_params hash_double_size_params; 29388c2ecf20Sopenharmony_ci struct devlink_resource_size_params linear_size_params; 29398c2ecf20Sopenharmony_ci struct devlink_resource_size_params kvd_size_params; 29408c2ecf20Sopenharmony_ci u32 kvd_size, single_size, double_size, linear_size; 29418c2ecf20Sopenharmony_ci const struct mlxsw_config_profile *profile; 29428c2ecf20Sopenharmony_ci int err; 29438c2ecf20Sopenharmony_ci 29448c2ecf20Sopenharmony_ci profile = &mlxsw_sp1_config_profile; 29458c2ecf20Sopenharmony_ci if (!MLXSW_CORE_RES_VALID(mlxsw_core, KVD_SIZE)) 29468c2ecf20Sopenharmony_ci return -EIO; 29478c2ecf20Sopenharmony_ci 29488c2ecf20Sopenharmony_ci mlxsw_sp_resource_size_params_prepare(mlxsw_core, &kvd_size_params, 29498c2ecf20Sopenharmony_ci &linear_size_params, 29508c2ecf20Sopenharmony_ci &hash_double_size_params, 29518c2ecf20Sopenharmony_ci &hash_single_size_params); 29528c2ecf20Sopenharmony_ci 29538c2ecf20Sopenharmony_ci kvd_size = MLXSW_CORE_RES_GET(mlxsw_core, KVD_SIZE); 29548c2ecf20Sopenharmony_ci err = devlink_resource_register(devlink, MLXSW_SP_RESOURCE_NAME_KVD, 29558c2ecf20Sopenharmony_ci kvd_size, MLXSW_SP_RESOURCE_KVD, 29568c2ecf20Sopenharmony_ci DEVLINK_RESOURCE_ID_PARENT_TOP, 29578c2ecf20Sopenharmony_ci &kvd_size_params); 29588c2ecf20Sopenharmony_ci if (err) 29598c2ecf20Sopenharmony_ci return err; 29608c2ecf20Sopenharmony_ci 29618c2ecf20Sopenharmony_ci linear_size = profile->kvd_linear_size; 29628c2ecf20Sopenharmony_ci err = devlink_resource_register(devlink, MLXSW_SP_RESOURCE_NAME_KVD_LINEAR, 29638c2ecf20Sopenharmony_ci linear_size, 29648c2ecf20Sopenharmony_ci MLXSW_SP_RESOURCE_KVD_LINEAR, 29658c2ecf20Sopenharmony_ci MLXSW_SP_RESOURCE_KVD, 29668c2ecf20Sopenharmony_ci &linear_size_params); 29678c2ecf20Sopenharmony_ci if (err) 29688c2ecf20Sopenharmony_ci return err; 29698c2ecf20Sopenharmony_ci 29708c2ecf20Sopenharmony_ci err = mlxsw_sp1_kvdl_resources_register(mlxsw_core); 29718c2ecf20Sopenharmony_ci if (err) 29728c2ecf20Sopenharmony_ci return err; 29738c2ecf20Sopenharmony_ci 29748c2ecf20Sopenharmony_ci double_size = kvd_size - linear_size; 29758c2ecf20Sopenharmony_ci double_size *= profile->kvd_hash_double_parts; 29768c2ecf20Sopenharmony_ci double_size /= profile->kvd_hash_double_parts + 29778c2ecf20Sopenharmony_ci profile->kvd_hash_single_parts; 29788c2ecf20Sopenharmony_ci double_size = rounddown(double_size, MLXSW_SP_KVD_GRANULARITY); 29798c2ecf20Sopenharmony_ci err = devlink_resource_register(devlink, MLXSW_SP_RESOURCE_NAME_KVD_HASH_DOUBLE, 29808c2ecf20Sopenharmony_ci double_size, 29818c2ecf20Sopenharmony_ci MLXSW_SP_RESOURCE_KVD_HASH_DOUBLE, 29828c2ecf20Sopenharmony_ci MLXSW_SP_RESOURCE_KVD, 29838c2ecf20Sopenharmony_ci &hash_double_size_params); 29848c2ecf20Sopenharmony_ci if (err) 29858c2ecf20Sopenharmony_ci return err; 29868c2ecf20Sopenharmony_ci 29878c2ecf20Sopenharmony_ci single_size = kvd_size - double_size - linear_size; 29888c2ecf20Sopenharmony_ci err = devlink_resource_register(devlink, MLXSW_SP_RESOURCE_NAME_KVD_HASH_SINGLE, 29898c2ecf20Sopenharmony_ci single_size, 29908c2ecf20Sopenharmony_ci MLXSW_SP_RESOURCE_KVD_HASH_SINGLE, 29918c2ecf20Sopenharmony_ci MLXSW_SP_RESOURCE_KVD, 29928c2ecf20Sopenharmony_ci &hash_single_size_params); 29938c2ecf20Sopenharmony_ci if (err) 29948c2ecf20Sopenharmony_ci return err; 29958c2ecf20Sopenharmony_ci 29968c2ecf20Sopenharmony_ci return 0; 29978c2ecf20Sopenharmony_ci} 29988c2ecf20Sopenharmony_ci 29998c2ecf20Sopenharmony_cistatic int mlxsw_sp2_resources_kvd_register(struct mlxsw_core *mlxsw_core) 30008c2ecf20Sopenharmony_ci{ 30018c2ecf20Sopenharmony_ci struct devlink *devlink = priv_to_devlink(mlxsw_core); 30028c2ecf20Sopenharmony_ci struct devlink_resource_size_params kvd_size_params; 30038c2ecf20Sopenharmony_ci u32 kvd_size; 30048c2ecf20Sopenharmony_ci 30058c2ecf20Sopenharmony_ci if (!MLXSW_CORE_RES_VALID(mlxsw_core, KVD_SIZE)) 30068c2ecf20Sopenharmony_ci return -EIO; 30078c2ecf20Sopenharmony_ci 30088c2ecf20Sopenharmony_ci kvd_size = MLXSW_CORE_RES_GET(mlxsw_core, KVD_SIZE); 30098c2ecf20Sopenharmony_ci devlink_resource_size_params_init(&kvd_size_params, kvd_size, kvd_size, 30108c2ecf20Sopenharmony_ci MLXSW_SP_KVD_GRANULARITY, 30118c2ecf20Sopenharmony_ci DEVLINK_RESOURCE_UNIT_ENTRY); 30128c2ecf20Sopenharmony_ci 30138c2ecf20Sopenharmony_ci return devlink_resource_register(devlink, MLXSW_SP_RESOURCE_NAME_KVD, 30148c2ecf20Sopenharmony_ci kvd_size, MLXSW_SP_RESOURCE_KVD, 30158c2ecf20Sopenharmony_ci DEVLINK_RESOURCE_ID_PARENT_TOP, 30168c2ecf20Sopenharmony_ci &kvd_size_params); 30178c2ecf20Sopenharmony_ci} 30188c2ecf20Sopenharmony_ci 30198c2ecf20Sopenharmony_cistatic int mlxsw_sp_resources_span_register(struct mlxsw_core *mlxsw_core) 30208c2ecf20Sopenharmony_ci{ 30218c2ecf20Sopenharmony_ci struct devlink *devlink = priv_to_devlink(mlxsw_core); 30228c2ecf20Sopenharmony_ci struct devlink_resource_size_params span_size_params; 30238c2ecf20Sopenharmony_ci u32 max_span; 30248c2ecf20Sopenharmony_ci 30258c2ecf20Sopenharmony_ci if (!MLXSW_CORE_RES_VALID(mlxsw_core, MAX_SPAN)) 30268c2ecf20Sopenharmony_ci return -EIO; 30278c2ecf20Sopenharmony_ci 30288c2ecf20Sopenharmony_ci max_span = MLXSW_CORE_RES_GET(mlxsw_core, MAX_SPAN); 30298c2ecf20Sopenharmony_ci devlink_resource_size_params_init(&span_size_params, max_span, max_span, 30308c2ecf20Sopenharmony_ci 1, DEVLINK_RESOURCE_UNIT_ENTRY); 30318c2ecf20Sopenharmony_ci 30328c2ecf20Sopenharmony_ci return devlink_resource_register(devlink, MLXSW_SP_RESOURCE_NAME_SPAN, 30338c2ecf20Sopenharmony_ci max_span, MLXSW_SP_RESOURCE_SPAN, 30348c2ecf20Sopenharmony_ci DEVLINK_RESOURCE_ID_PARENT_TOP, 30358c2ecf20Sopenharmony_ci &span_size_params); 30368c2ecf20Sopenharmony_ci} 30378c2ecf20Sopenharmony_ci 30388c2ecf20Sopenharmony_cistatic int mlxsw_sp1_resources_register(struct mlxsw_core *mlxsw_core) 30398c2ecf20Sopenharmony_ci{ 30408c2ecf20Sopenharmony_ci int err; 30418c2ecf20Sopenharmony_ci 30428c2ecf20Sopenharmony_ci err = mlxsw_sp1_resources_kvd_register(mlxsw_core); 30438c2ecf20Sopenharmony_ci if (err) 30448c2ecf20Sopenharmony_ci return err; 30458c2ecf20Sopenharmony_ci 30468c2ecf20Sopenharmony_ci err = mlxsw_sp_resources_span_register(mlxsw_core); 30478c2ecf20Sopenharmony_ci if (err) 30488c2ecf20Sopenharmony_ci goto err_resources_span_register; 30498c2ecf20Sopenharmony_ci 30508c2ecf20Sopenharmony_ci err = mlxsw_sp_counter_resources_register(mlxsw_core); 30518c2ecf20Sopenharmony_ci if (err) 30528c2ecf20Sopenharmony_ci goto err_resources_counter_register; 30538c2ecf20Sopenharmony_ci 30548c2ecf20Sopenharmony_ci err = mlxsw_sp_policer_resources_register(mlxsw_core); 30558c2ecf20Sopenharmony_ci if (err) 30568c2ecf20Sopenharmony_ci goto err_resources_counter_register; 30578c2ecf20Sopenharmony_ci 30588c2ecf20Sopenharmony_ci return 0; 30598c2ecf20Sopenharmony_ci 30608c2ecf20Sopenharmony_cierr_resources_counter_register: 30618c2ecf20Sopenharmony_cierr_resources_span_register: 30628c2ecf20Sopenharmony_ci devlink_resources_unregister(priv_to_devlink(mlxsw_core), NULL); 30638c2ecf20Sopenharmony_ci return err; 30648c2ecf20Sopenharmony_ci} 30658c2ecf20Sopenharmony_ci 30668c2ecf20Sopenharmony_cistatic int mlxsw_sp2_resources_register(struct mlxsw_core *mlxsw_core) 30678c2ecf20Sopenharmony_ci{ 30688c2ecf20Sopenharmony_ci int err; 30698c2ecf20Sopenharmony_ci 30708c2ecf20Sopenharmony_ci err = mlxsw_sp2_resources_kvd_register(mlxsw_core); 30718c2ecf20Sopenharmony_ci if (err) 30728c2ecf20Sopenharmony_ci return err; 30738c2ecf20Sopenharmony_ci 30748c2ecf20Sopenharmony_ci err = mlxsw_sp_resources_span_register(mlxsw_core); 30758c2ecf20Sopenharmony_ci if (err) 30768c2ecf20Sopenharmony_ci goto err_resources_span_register; 30778c2ecf20Sopenharmony_ci 30788c2ecf20Sopenharmony_ci err = mlxsw_sp_counter_resources_register(mlxsw_core); 30798c2ecf20Sopenharmony_ci if (err) 30808c2ecf20Sopenharmony_ci goto err_resources_counter_register; 30818c2ecf20Sopenharmony_ci 30828c2ecf20Sopenharmony_ci err = mlxsw_sp_policer_resources_register(mlxsw_core); 30838c2ecf20Sopenharmony_ci if (err) 30848c2ecf20Sopenharmony_ci goto err_resources_counter_register; 30858c2ecf20Sopenharmony_ci 30868c2ecf20Sopenharmony_ci return 0; 30878c2ecf20Sopenharmony_ci 30888c2ecf20Sopenharmony_cierr_resources_counter_register: 30898c2ecf20Sopenharmony_cierr_resources_span_register: 30908c2ecf20Sopenharmony_ci devlink_resources_unregister(priv_to_devlink(mlxsw_core), NULL); 30918c2ecf20Sopenharmony_ci return err; 30928c2ecf20Sopenharmony_ci} 30938c2ecf20Sopenharmony_ci 30948c2ecf20Sopenharmony_cistatic int mlxsw_sp_kvd_sizes_get(struct mlxsw_core *mlxsw_core, 30958c2ecf20Sopenharmony_ci const struct mlxsw_config_profile *profile, 30968c2ecf20Sopenharmony_ci u64 *p_single_size, u64 *p_double_size, 30978c2ecf20Sopenharmony_ci u64 *p_linear_size) 30988c2ecf20Sopenharmony_ci{ 30998c2ecf20Sopenharmony_ci struct devlink *devlink = priv_to_devlink(mlxsw_core); 31008c2ecf20Sopenharmony_ci u32 double_size; 31018c2ecf20Sopenharmony_ci int err; 31028c2ecf20Sopenharmony_ci 31038c2ecf20Sopenharmony_ci if (!MLXSW_CORE_RES_VALID(mlxsw_core, KVD_SINGLE_MIN_SIZE) || 31048c2ecf20Sopenharmony_ci !MLXSW_CORE_RES_VALID(mlxsw_core, KVD_DOUBLE_MIN_SIZE)) 31058c2ecf20Sopenharmony_ci return -EIO; 31068c2ecf20Sopenharmony_ci 31078c2ecf20Sopenharmony_ci /* The hash part is what left of the kvd without the 31088c2ecf20Sopenharmony_ci * linear part. It is split to the single size and 31098c2ecf20Sopenharmony_ci * double size by the parts ratio from the profile. 31108c2ecf20Sopenharmony_ci * Both sizes must be a multiplications of the 31118c2ecf20Sopenharmony_ci * granularity from the profile. In case the user 31128c2ecf20Sopenharmony_ci * provided the sizes they are obtained via devlink. 31138c2ecf20Sopenharmony_ci */ 31148c2ecf20Sopenharmony_ci err = devlink_resource_size_get(devlink, 31158c2ecf20Sopenharmony_ci MLXSW_SP_RESOURCE_KVD_LINEAR, 31168c2ecf20Sopenharmony_ci p_linear_size); 31178c2ecf20Sopenharmony_ci if (err) 31188c2ecf20Sopenharmony_ci *p_linear_size = profile->kvd_linear_size; 31198c2ecf20Sopenharmony_ci 31208c2ecf20Sopenharmony_ci err = devlink_resource_size_get(devlink, 31218c2ecf20Sopenharmony_ci MLXSW_SP_RESOURCE_KVD_HASH_DOUBLE, 31228c2ecf20Sopenharmony_ci p_double_size); 31238c2ecf20Sopenharmony_ci if (err) { 31248c2ecf20Sopenharmony_ci double_size = MLXSW_CORE_RES_GET(mlxsw_core, KVD_SIZE) - 31258c2ecf20Sopenharmony_ci *p_linear_size; 31268c2ecf20Sopenharmony_ci double_size *= profile->kvd_hash_double_parts; 31278c2ecf20Sopenharmony_ci double_size /= profile->kvd_hash_double_parts + 31288c2ecf20Sopenharmony_ci profile->kvd_hash_single_parts; 31298c2ecf20Sopenharmony_ci *p_double_size = rounddown(double_size, 31308c2ecf20Sopenharmony_ci MLXSW_SP_KVD_GRANULARITY); 31318c2ecf20Sopenharmony_ci } 31328c2ecf20Sopenharmony_ci 31338c2ecf20Sopenharmony_ci err = devlink_resource_size_get(devlink, 31348c2ecf20Sopenharmony_ci MLXSW_SP_RESOURCE_KVD_HASH_SINGLE, 31358c2ecf20Sopenharmony_ci p_single_size); 31368c2ecf20Sopenharmony_ci if (err) 31378c2ecf20Sopenharmony_ci *p_single_size = MLXSW_CORE_RES_GET(mlxsw_core, KVD_SIZE) - 31388c2ecf20Sopenharmony_ci *p_double_size - *p_linear_size; 31398c2ecf20Sopenharmony_ci 31408c2ecf20Sopenharmony_ci /* Check results are legal. */ 31418c2ecf20Sopenharmony_ci if (*p_single_size < MLXSW_CORE_RES_GET(mlxsw_core, KVD_SINGLE_MIN_SIZE) || 31428c2ecf20Sopenharmony_ci *p_double_size < MLXSW_CORE_RES_GET(mlxsw_core, KVD_DOUBLE_MIN_SIZE) || 31438c2ecf20Sopenharmony_ci MLXSW_CORE_RES_GET(mlxsw_core, KVD_SIZE) < *p_linear_size) 31448c2ecf20Sopenharmony_ci return -EIO; 31458c2ecf20Sopenharmony_ci 31468c2ecf20Sopenharmony_ci return 0; 31478c2ecf20Sopenharmony_ci} 31488c2ecf20Sopenharmony_ci 31498c2ecf20Sopenharmony_cistatic int 31508c2ecf20Sopenharmony_cimlxsw_sp_params_acl_region_rehash_intrvl_get(struct devlink *devlink, u32 id, 31518c2ecf20Sopenharmony_ci struct devlink_param_gset_ctx *ctx) 31528c2ecf20Sopenharmony_ci{ 31538c2ecf20Sopenharmony_ci struct mlxsw_core *mlxsw_core = devlink_priv(devlink); 31548c2ecf20Sopenharmony_ci struct mlxsw_sp *mlxsw_sp = mlxsw_core_driver_priv(mlxsw_core); 31558c2ecf20Sopenharmony_ci 31568c2ecf20Sopenharmony_ci ctx->val.vu32 = mlxsw_sp_acl_region_rehash_intrvl_get(mlxsw_sp); 31578c2ecf20Sopenharmony_ci return 0; 31588c2ecf20Sopenharmony_ci} 31598c2ecf20Sopenharmony_ci 31608c2ecf20Sopenharmony_cistatic int 31618c2ecf20Sopenharmony_cimlxsw_sp_params_acl_region_rehash_intrvl_set(struct devlink *devlink, u32 id, 31628c2ecf20Sopenharmony_ci struct devlink_param_gset_ctx *ctx) 31638c2ecf20Sopenharmony_ci{ 31648c2ecf20Sopenharmony_ci struct mlxsw_core *mlxsw_core = devlink_priv(devlink); 31658c2ecf20Sopenharmony_ci struct mlxsw_sp *mlxsw_sp = mlxsw_core_driver_priv(mlxsw_core); 31668c2ecf20Sopenharmony_ci 31678c2ecf20Sopenharmony_ci return mlxsw_sp_acl_region_rehash_intrvl_set(mlxsw_sp, ctx->val.vu32); 31688c2ecf20Sopenharmony_ci} 31698c2ecf20Sopenharmony_ci 31708c2ecf20Sopenharmony_cistatic const struct devlink_param mlxsw_sp2_devlink_params[] = { 31718c2ecf20Sopenharmony_ci DEVLINK_PARAM_DRIVER(MLXSW_DEVLINK_PARAM_ID_ACL_REGION_REHASH_INTERVAL, 31728c2ecf20Sopenharmony_ci "acl_region_rehash_interval", 31738c2ecf20Sopenharmony_ci DEVLINK_PARAM_TYPE_U32, 31748c2ecf20Sopenharmony_ci BIT(DEVLINK_PARAM_CMODE_RUNTIME), 31758c2ecf20Sopenharmony_ci mlxsw_sp_params_acl_region_rehash_intrvl_get, 31768c2ecf20Sopenharmony_ci mlxsw_sp_params_acl_region_rehash_intrvl_set, 31778c2ecf20Sopenharmony_ci NULL), 31788c2ecf20Sopenharmony_ci}; 31798c2ecf20Sopenharmony_ci 31808c2ecf20Sopenharmony_cistatic int mlxsw_sp2_params_register(struct mlxsw_core *mlxsw_core) 31818c2ecf20Sopenharmony_ci{ 31828c2ecf20Sopenharmony_ci struct devlink *devlink = priv_to_devlink(mlxsw_core); 31838c2ecf20Sopenharmony_ci union devlink_param_value value; 31848c2ecf20Sopenharmony_ci int err; 31858c2ecf20Sopenharmony_ci 31868c2ecf20Sopenharmony_ci err = devlink_params_register(devlink, mlxsw_sp2_devlink_params, 31878c2ecf20Sopenharmony_ci ARRAY_SIZE(mlxsw_sp2_devlink_params)); 31888c2ecf20Sopenharmony_ci if (err) 31898c2ecf20Sopenharmony_ci return err; 31908c2ecf20Sopenharmony_ci 31918c2ecf20Sopenharmony_ci value.vu32 = 0; 31928c2ecf20Sopenharmony_ci devlink_param_driverinit_value_set(devlink, 31938c2ecf20Sopenharmony_ci MLXSW_DEVLINK_PARAM_ID_ACL_REGION_REHASH_INTERVAL, 31948c2ecf20Sopenharmony_ci value); 31958c2ecf20Sopenharmony_ci return 0; 31968c2ecf20Sopenharmony_ci} 31978c2ecf20Sopenharmony_ci 31988c2ecf20Sopenharmony_cistatic void mlxsw_sp2_params_unregister(struct mlxsw_core *mlxsw_core) 31998c2ecf20Sopenharmony_ci{ 32008c2ecf20Sopenharmony_ci devlink_params_unregister(priv_to_devlink(mlxsw_core), 32018c2ecf20Sopenharmony_ci mlxsw_sp2_devlink_params, 32028c2ecf20Sopenharmony_ci ARRAY_SIZE(mlxsw_sp2_devlink_params)); 32038c2ecf20Sopenharmony_ci} 32048c2ecf20Sopenharmony_ci 32058c2ecf20Sopenharmony_cistatic void mlxsw_sp_ptp_transmitted(struct mlxsw_core *mlxsw_core, 32068c2ecf20Sopenharmony_ci struct sk_buff *skb, u8 local_port) 32078c2ecf20Sopenharmony_ci{ 32088c2ecf20Sopenharmony_ci struct mlxsw_sp *mlxsw_sp = mlxsw_core_driver_priv(mlxsw_core); 32098c2ecf20Sopenharmony_ci 32108c2ecf20Sopenharmony_ci skb_pull(skb, MLXSW_TXHDR_LEN); 32118c2ecf20Sopenharmony_ci mlxsw_sp->ptp_ops->transmitted(mlxsw_sp, skb, local_port); 32128c2ecf20Sopenharmony_ci} 32138c2ecf20Sopenharmony_ci 32148c2ecf20Sopenharmony_cistatic struct mlxsw_driver mlxsw_sp1_driver = { 32158c2ecf20Sopenharmony_ci .kind = mlxsw_sp1_driver_name, 32168c2ecf20Sopenharmony_ci .priv_size = sizeof(struct mlxsw_sp), 32178c2ecf20Sopenharmony_ci .fw_req_rev = &mlxsw_sp1_fw_rev, 32188c2ecf20Sopenharmony_ci .fw_filename = MLXSW_SP1_FW_FILENAME, 32198c2ecf20Sopenharmony_ci .init = mlxsw_sp1_init, 32208c2ecf20Sopenharmony_ci .fini = mlxsw_sp_fini, 32218c2ecf20Sopenharmony_ci .basic_trap_groups_set = mlxsw_sp_basic_trap_groups_set, 32228c2ecf20Sopenharmony_ci .port_split = mlxsw_sp_port_split, 32238c2ecf20Sopenharmony_ci .port_unsplit = mlxsw_sp_port_unsplit, 32248c2ecf20Sopenharmony_ci .sb_pool_get = mlxsw_sp_sb_pool_get, 32258c2ecf20Sopenharmony_ci .sb_pool_set = mlxsw_sp_sb_pool_set, 32268c2ecf20Sopenharmony_ci .sb_port_pool_get = mlxsw_sp_sb_port_pool_get, 32278c2ecf20Sopenharmony_ci .sb_port_pool_set = mlxsw_sp_sb_port_pool_set, 32288c2ecf20Sopenharmony_ci .sb_tc_pool_bind_get = mlxsw_sp_sb_tc_pool_bind_get, 32298c2ecf20Sopenharmony_ci .sb_tc_pool_bind_set = mlxsw_sp_sb_tc_pool_bind_set, 32308c2ecf20Sopenharmony_ci .sb_occ_snapshot = mlxsw_sp_sb_occ_snapshot, 32318c2ecf20Sopenharmony_ci .sb_occ_max_clear = mlxsw_sp_sb_occ_max_clear, 32328c2ecf20Sopenharmony_ci .sb_occ_port_pool_get = mlxsw_sp_sb_occ_port_pool_get, 32338c2ecf20Sopenharmony_ci .sb_occ_tc_port_bind_get = mlxsw_sp_sb_occ_tc_port_bind_get, 32348c2ecf20Sopenharmony_ci .trap_init = mlxsw_sp_trap_init, 32358c2ecf20Sopenharmony_ci .trap_fini = mlxsw_sp_trap_fini, 32368c2ecf20Sopenharmony_ci .trap_action_set = mlxsw_sp_trap_action_set, 32378c2ecf20Sopenharmony_ci .trap_group_init = mlxsw_sp_trap_group_init, 32388c2ecf20Sopenharmony_ci .trap_group_set = mlxsw_sp_trap_group_set, 32398c2ecf20Sopenharmony_ci .trap_policer_init = mlxsw_sp_trap_policer_init, 32408c2ecf20Sopenharmony_ci .trap_policer_fini = mlxsw_sp_trap_policer_fini, 32418c2ecf20Sopenharmony_ci .trap_policer_set = mlxsw_sp_trap_policer_set, 32428c2ecf20Sopenharmony_ci .trap_policer_counter_get = mlxsw_sp_trap_policer_counter_get, 32438c2ecf20Sopenharmony_ci .txhdr_construct = mlxsw_sp_txhdr_construct, 32448c2ecf20Sopenharmony_ci .resources_register = mlxsw_sp1_resources_register, 32458c2ecf20Sopenharmony_ci .kvd_sizes_get = mlxsw_sp_kvd_sizes_get, 32468c2ecf20Sopenharmony_ci .ptp_transmitted = mlxsw_sp_ptp_transmitted, 32478c2ecf20Sopenharmony_ci .txhdr_len = MLXSW_TXHDR_LEN, 32488c2ecf20Sopenharmony_ci .profile = &mlxsw_sp1_config_profile, 32498c2ecf20Sopenharmony_ci .res_query_enabled = true, 32508c2ecf20Sopenharmony_ci .fw_fatal_enabled = true, 32518c2ecf20Sopenharmony_ci .temp_warn_enabled = true, 32528c2ecf20Sopenharmony_ci}; 32538c2ecf20Sopenharmony_ci 32548c2ecf20Sopenharmony_cistatic struct mlxsw_driver mlxsw_sp2_driver = { 32558c2ecf20Sopenharmony_ci .kind = mlxsw_sp2_driver_name, 32568c2ecf20Sopenharmony_ci .priv_size = sizeof(struct mlxsw_sp), 32578c2ecf20Sopenharmony_ci .fw_req_rev = &mlxsw_sp2_fw_rev, 32588c2ecf20Sopenharmony_ci .fw_filename = MLXSW_SP2_FW_FILENAME, 32598c2ecf20Sopenharmony_ci .init = mlxsw_sp2_init, 32608c2ecf20Sopenharmony_ci .fini = mlxsw_sp_fini, 32618c2ecf20Sopenharmony_ci .basic_trap_groups_set = mlxsw_sp_basic_trap_groups_set, 32628c2ecf20Sopenharmony_ci .port_split = mlxsw_sp_port_split, 32638c2ecf20Sopenharmony_ci .port_unsplit = mlxsw_sp_port_unsplit, 32648c2ecf20Sopenharmony_ci .sb_pool_get = mlxsw_sp_sb_pool_get, 32658c2ecf20Sopenharmony_ci .sb_pool_set = mlxsw_sp_sb_pool_set, 32668c2ecf20Sopenharmony_ci .sb_port_pool_get = mlxsw_sp_sb_port_pool_get, 32678c2ecf20Sopenharmony_ci .sb_port_pool_set = mlxsw_sp_sb_port_pool_set, 32688c2ecf20Sopenharmony_ci .sb_tc_pool_bind_get = mlxsw_sp_sb_tc_pool_bind_get, 32698c2ecf20Sopenharmony_ci .sb_tc_pool_bind_set = mlxsw_sp_sb_tc_pool_bind_set, 32708c2ecf20Sopenharmony_ci .sb_occ_snapshot = mlxsw_sp_sb_occ_snapshot, 32718c2ecf20Sopenharmony_ci .sb_occ_max_clear = mlxsw_sp_sb_occ_max_clear, 32728c2ecf20Sopenharmony_ci .sb_occ_port_pool_get = mlxsw_sp_sb_occ_port_pool_get, 32738c2ecf20Sopenharmony_ci .sb_occ_tc_port_bind_get = mlxsw_sp_sb_occ_tc_port_bind_get, 32748c2ecf20Sopenharmony_ci .trap_init = mlxsw_sp_trap_init, 32758c2ecf20Sopenharmony_ci .trap_fini = mlxsw_sp_trap_fini, 32768c2ecf20Sopenharmony_ci .trap_action_set = mlxsw_sp_trap_action_set, 32778c2ecf20Sopenharmony_ci .trap_group_init = mlxsw_sp_trap_group_init, 32788c2ecf20Sopenharmony_ci .trap_group_set = mlxsw_sp_trap_group_set, 32798c2ecf20Sopenharmony_ci .trap_policer_init = mlxsw_sp_trap_policer_init, 32808c2ecf20Sopenharmony_ci .trap_policer_fini = mlxsw_sp_trap_policer_fini, 32818c2ecf20Sopenharmony_ci .trap_policer_set = mlxsw_sp_trap_policer_set, 32828c2ecf20Sopenharmony_ci .trap_policer_counter_get = mlxsw_sp_trap_policer_counter_get, 32838c2ecf20Sopenharmony_ci .txhdr_construct = mlxsw_sp_txhdr_construct, 32848c2ecf20Sopenharmony_ci .resources_register = mlxsw_sp2_resources_register, 32858c2ecf20Sopenharmony_ci .params_register = mlxsw_sp2_params_register, 32868c2ecf20Sopenharmony_ci .params_unregister = mlxsw_sp2_params_unregister, 32878c2ecf20Sopenharmony_ci .ptp_transmitted = mlxsw_sp_ptp_transmitted, 32888c2ecf20Sopenharmony_ci .txhdr_len = MLXSW_TXHDR_LEN, 32898c2ecf20Sopenharmony_ci .profile = &mlxsw_sp2_config_profile, 32908c2ecf20Sopenharmony_ci .res_query_enabled = true, 32918c2ecf20Sopenharmony_ci .fw_fatal_enabled = true, 32928c2ecf20Sopenharmony_ci .temp_warn_enabled = true, 32938c2ecf20Sopenharmony_ci}; 32948c2ecf20Sopenharmony_ci 32958c2ecf20Sopenharmony_cistatic struct mlxsw_driver mlxsw_sp3_driver = { 32968c2ecf20Sopenharmony_ci .kind = mlxsw_sp3_driver_name, 32978c2ecf20Sopenharmony_ci .priv_size = sizeof(struct mlxsw_sp), 32988c2ecf20Sopenharmony_ci .fw_req_rev = &mlxsw_sp3_fw_rev, 32998c2ecf20Sopenharmony_ci .fw_filename = MLXSW_SP3_FW_FILENAME, 33008c2ecf20Sopenharmony_ci .init = mlxsw_sp3_init, 33018c2ecf20Sopenharmony_ci .fini = mlxsw_sp_fini, 33028c2ecf20Sopenharmony_ci .basic_trap_groups_set = mlxsw_sp_basic_trap_groups_set, 33038c2ecf20Sopenharmony_ci .port_split = mlxsw_sp_port_split, 33048c2ecf20Sopenharmony_ci .port_unsplit = mlxsw_sp_port_unsplit, 33058c2ecf20Sopenharmony_ci .sb_pool_get = mlxsw_sp_sb_pool_get, 33068c2ecf20Sopenharmony_ci .sb_pool_set = mlxsw_sp_sb_pool_set, 33078c2ecf20Sopenharmony_ci .sb_port_pool_get = mlxsw_sp_sb_port_pool_get, 33088c2ecf20Sopenharmony_ci .sb_port_pool_set = mlxsw_sp_sb_port_pool_set, 33098c2ecf20Sopenharmony_ci .sb_tc_pool_bind_get = mlxsw_sp_sb_tc_pool_bind_get, 33108c2ecf20Sopenharmony_ci .sb_tc_pool_bind_set = mlxsw_sp_sb_tc_pool_bind_set, 33118c2ecf20Sopenharmony_ci .sb_occ_snapshot = mlxsw_sp_sb_occ_snapshot, 33128c2ecf20Sopenharmony_ci .sb_occ_max_clear = mlxsw_sp_sb_occ_max_clear, 33138c2ecf20Sopenharmony_ci .sb_occ_port_pool_get = mlxsw_sp_sb_occ_port_pool_get, 33148c2ecf20Sopenharmony_ci .sb_occ_tc_port_bind_get = mlxsw_sp_sb_occ_tc_port_bind_get, 33158c2ecf20Sopenharmony_ci .trap_init = mlxsw_sp_trap_init, 33168c2ecf20Sopenharmony_ci .trap_fini = mlxsw_sp_trap_fini, 33178c2ecf20Sopenharmony_ci .trap_action_set = mlxsw_sp_trap_action_set, 33188c2ecf20Sopenharmony_ci .trap_group_init = mlxsw_sp_trap_group_init, 33198c2ecf20Sopenharmony_ci .trap_group_set = mlxsw_sp_trap_group_set, 33208c2ecf20Sopenharmony_ci .trap_policer_init = mlxsw_sp_trap_policer_init, 33218c2ecf20Sopenharmony_ci .trap_policer_fini = mlxsw_sp_trap_policer_fini, 33228c2ecf20Sopenharmony_ci .trap_policer_set = mlxsw_sp_trap_policer_set, 33238c2ecf20Sopenharmony_ci .trap_policer_counter_get = mlxsw_sp_trap_policer_counter_get, 33248c2ecf20Sopenharmony_ci .txhdr_construct = mlxsw_sp_txhdr_construct, 33258c2ecf20Sopenharmony_ci .resources_register = mlxsw_sp2_resources_register, 33268c2ecf20Sopenharmony_ci .params_register = mlxsw_sp2_params_register, 33278c2ecf20Sopenharmony_ci .params_unregister = mlxsw_sp2_params_unregister, 33288c2ecf20Sopenharmony_ci .ptp_transmitted = mlxsw_sp_ptp_transmitted, 33298c2ecf20Sopenharmony_ci .txhdr_len = MLXSW_TXHDR_LEN, 33308c2ecf20Sopenharmony_ci .profile = &mlxsw_sp2_config_profile, 33318c2ecf20Sopenharmony_ci .res_query_enabled = true, 33328c2ecf20Sopenharmony_ci .fw_fatal_enabled = true, 33338c2ecf20Sopenharmony_ci .temp_warn_enabled = true, 33348c2ecf20Sopenharmony_ci}; 33358c2ecf20Sopenharmony_ci 33368c2ecf20Sopenharmony_cibool mlxsw_sp_port_dev_check(const struct net_device *dev) 33378c2ecf20Sopenharmony_ci{ 33388c2ecf20Sopenharmony_ci return dev->netdev_ops == &mlxsw_sp_port_netdev_ops; 33398c2ecf20Sopenharmony_ci} 33408c2ecf20Sopenharmony_ci 33418c2ecf20Sopenharmony_cistatic int mlxsw_sp_lower_dev_walk(struct net_device *lower_dev, 33428c2ecf20Sopenharmony_ci struct netdev_nested_priv *priv) 33438c2ecf20Sopenharmony_ci{ 33448c2ecf20Sopenharmony_ci int ret = 0; 33458c2ecf20Sopenharmony_ci 33468c2ecf20Sopenharmony_ci if (mlxsw_sp_port_dev_check(lower_dev)) { 33478c2ecf20Sopenharmony_ci priv->data = (void *)netdev_priv(lower_dev); 33488c2ecf20Sopenharmony_ci ret = 1; 33498c2ecf20Sopenharmony_ci } 33508c2ecf20Sopenharmony_ci 33518c2ecf20Sopenharmony_ci return ret; 33528c2ecf20Sopenharmony_ci} 33538c2ecf20Sopenharmony_ci 33548c2ecf20Sopenharmony_cistruct mlxsw_sp_port *mlxsw_sp_port_dev_lower_find(struct net_device *dev) 33558c2ecf20Sopenharmony_ci{ 33568c2ecf20Sopenharmony_ci struct netdev_nested_priv priv = { 33578c2ecf20Sopenharmony_ci .data = NULL, 33588c2ecf20Sopenharmony_ci }; 33598c2ecf20Sopenharmony_ci 33608c2ecf20Sopenharmony_ci if (mlxsw_sp_port_dev_check(dev)) 33618c2ecf20Sopenharmony_ci return netdev_priv(dev); 33628c2ecf20Sopenharmony_ci 33638c2ecf20Sopenharmony_ci netdev_walk_all_lower_dev(dev, mlxsw_sp_lower_dev_walk, &priv); 33648c2ecf20Sopenharmony_ci 33658c2ecf20Sopenharmony_ci return (struct mlxsw_sp_port *)priv.data; 33668c2ecf20Sopenharmony_ci} 33678c2ecf20Sopenharmony_ci 33688c2ecf20Sopenharmony_cistruct mlxsw_sp *mlxsw_sp_lower_get(struct net_device *dev) 33698c2ecf20Sopenharmony_ci{ 33708c2ecf20Sopenharmony_ci struct mlxsw_sp_port *mlxsw_sp_port; 33718c2ecf20Sopenharmony_ci 33728c2ecf20Sopenharmony_ci mlxsw_sp_port = mlxsw_sp_port_dev_lower_find(dev); 33738c2ecf20Sopenharmony_ci return mlxsw_sp_port ? mlxsw_sp_port->mlxsw_sp : NULL; 33748c2ecf20Sopenharmony_ci} 33758c2ecf20Sopenharmony_ci 33768c2ecf20Sopenharmony_cistruct mlxsw_sp_port *mlxsw_sp_port_dev_lower_find_rcu(struct net_device *dev) 33778c2ecf20Sopenharmony_ci{ 33788c2ecf20Sopenharmony_ci struct netdev_nested_priv priv = { 33798c2ecf20Sopenharmony_ci .data = NULL, 33808c2ecf20Sopenharmony_ci }; 33818c2ecf20Sopenharmony_ci 33828c2ecf20Sopenharmony_ci if (mlxsw_sp_port_dev_check(dev)) 33838c2ecf20Sopenharmony_ci return netdev_priv(dev); 33848c2ecf20Sopenharmony_ci 33858c2ecf20Sopenharmony_ci netdev_walk_all_lower_dev_rcu(dev, mlxsw_sp_lower_dev_walk, 33868c2ecf20Sopenharmony_ci &priv); 33878c2ecf20Sopenharmony_ci 33888c2ecf20Sopenharmony_ci return (struct mlxsw_sp_port *)priv.data; 33898c2ecf20Sopenharmony_ci} 33908c2ecf20Sopenharmony_ci 33918c2ecf20Sopenharmony_cistruct mlxsw_sp_port *mlxsw_sp_port_lower_dev_hold(struct net_device *dev) 33928c2ecf20Sopenharmony_ci{ 33938c2ecf20Sopenharmony_ci struct mlxsw_sp_port *mlxsw_sp_port; 33948c2ecf20Sopenharmony_ci 33958c2ecf20Sopenharmony_ci rcu_read_lock(); 33968c2ecf20Sopenharmony_ci mlxsw_sp_port = mlxsw_sp_port_dev_lower_find_rcu(dev); 33978c2ecf20Sopenharmony_ci if (mlxsw_sp_port) 33988c2ecf20Sopenharmony_ci dev_hold(mlxsw_sp_port->dev); 33998c2ecf20Sopenharmony_ci rcu_read_unlock(); 34008c2ecf20Sopenharmony_ci return mlxsw_sp_port; 34018c2ecf20Sopenharmony_ci} 34028c2ecf20Sopenharmony_ci 34038c2ecf20Sopenharmony_civoid mlxsw_sp_port_dev_put(struct mlxsw_sp_port *mlxsw_sp_port) 34048c2ecf20Sopenharmony_ci{ 34058c2ecf20Sopenharmony_ci dev_put(mlxsw_sp_port->dev); 34068c2ecf20Sopenharmony_ci} 34078c2ecf20Sopenharmony_ci 34088c2ecf20Sopenharmony_cistatic void 34098c2ecf20Sopenharmony_cimlxsw_sp_port_lag_uppers_cleanup(struct mlxsw_sp_port *mlxsw_sp_port, 34108c2ecf20Sopenharmony_ci struct net_device *lag_dev) 34118c2ecf20Sopenharmony_ci{ 34128c2ecf20Sopenharmony_ci struct net_device *br_dev = netdev_master_upper_dev_get(lag_dev); 34138c2ecf20Sopenharmony_ci struct net_device *upper_dev; 34148c2ecf20Sopenharmony_ci struct list_head *iter; 34158c2ecf20Sopenharmony_ci 34168c2ecf20Sopenharmony_ci if (netif_is_bridge_port(lag_dev)) 34178c2ecf20Sopenharmony_ci mlxsw_sp_port_bridge_leave(mlxsw_sp_port, lag_dev, br_dev); 34188c2ecf20Sopenharmony_ci 34198c2ecf20Sopenharmony_ci netdev_for_each_upper_dev_rcu(lag_dev, upper_dev, iter) { 34208c2ecf20Sopenharmony_ci if (!netif_is_bridge_port(upper_dev)) 34218c2ecf20Sopenharmony_ci continue; 34228c2ecf20Sopenharmony_ci br_dev = netdev_master_upper_dev_get(upper_dev); 34238c2ecf20Sopenharmony_ci mlxsw_sp_port_bridge_leave(mlxsw_sp_port, upper_dev, br_dev); 34248c2ecf20Sopenharmony_ci } 34258c2ecf20Sopenharmony_ci} 34268c2ecf20Sopenharmony_ci 34278c2ecf20Sopenharmony_cistatic int mlxsw_sp_lag_create(struct mlxsw_sp *mlxsw_sp, u16 lag_id) 34288c2ecf20Sopenharmony_ci{ 34298c2ecf20Sopenharmony_ci char sldr_pl[MLXSW_REG_SLDR_LEN]; 34308c2ecf20Sopenharmony_ci 34318c2ecf20Sopenharmony_ci mlxsw_reg_sldr_lag_create_pack(sldr_pl, lag_id); 34328c2ecf20Sopenharmony_ci return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(sldr), sldr_pl); 34338c2ecf20Sopenharmony_ci} 34348c2ecf20Sopenharmony_ci 34358c2ecf20Sopenharmony_cistatic int mlxsw_sp_lag_destroy(struct mlxsw_sp *mlxsw_sp, u16 lag_id) 34368c2ecf20Sopenharmony_ci{ 34378c2ecf20Sopenharmony_ci char sldr_pl[MLXSW_REG_SLDR_LEN]; 34388c2ecf20Sopenharmony_ci 34398c2ecf20Sopenharmony_ci mlxsw_reg_sldr_lag_destroy_pack(sldr_pl, lag_id); 34408c2ecf20Sopenharmony_ci return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(sldr), sldr_pl); 34418c2ecf20Sopenharmony_ci} 34428c2ecf20Sopenharmony_ci 34438c2ecf20Sopenharmony_cistatic int mlxsw_sp_lag_col_port_add(struct mlxsw_sp_port *mlxsw_sp_port, 34448c2ecf20Sopenharmony_ci u16 lag_id, u8 port_index) 34458c2ecf20Sopenharmony_ci{ 34468c2ecf20Sopenharmony_ci struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; 34478c2ecf20Sopenharmony_ci char slcor_pl[MLXSW_REG_SLCOR_LEN]; 34488c2ecf20Sopenharmony_ci 34498c2ecf20Sopenharmony_ci mlxsw_reg_slcor_port_add_pack(slcor_pl, mlxsw_sp_port->local_port, 34508c2ecf20Sopenharmony_ci lag_id, port_index); 34518c2ecf20Sopenharmony_ci return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(slcor), slcor_pl); 34528c2ecf20Sopenharmony_ci} 34538c2ecf20Sopenharmony_ci 34548c2ecf20Sopenharmony_cistatic int mlxsw_sp_lag_col_port_remove(struct mlxsw_sp_port *mlxsw_sp_port, 34558c2ecf20Sopenharmony_ci u16 lag_id) 34568c2ecf20Sopenharmony_ci{ 34578c2ecf20Sopenharmony_ci struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; 34588c2ecf20Sopenharmony_ci char slcor_pl[MLXSW_REG_SLCOR_LEN]; 34598c2ecf20Sopenharmony_ci 34608c2ecf20Sopenharmony_ci mlxsw_reg_slcor_port_remove_pack(slcor_pl, mlxsw_sp_port->local_port, 34618c2ecf20Sopenharmony_ci lag_id); 34628c2ecf20Sopenharmony_ci return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(slcor), slcor_pl); 34638c2ecf20Sopenharmony_ci} 34648c2ecf20Sopenharmony_ci 34658c2ecf20Sopenharmony_cistatic int mlxsw_sp_lag_col_port_enable(struct mlxsw_sp_port *mlxsw_sp_port, 34668c2ecf20Sopenharmony_ci u16 lag_id) 34678c2ecf20Sopenharmony_ci{ 34688c2ecf20Sopenharmony_ci struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; 34698c2ecf20Sopenharmony_ci char slcor_pl[MLXSW_REG_SLCOR_LEN]; 34708c2ecf20Sopenharmony_ci 34718c2ecf20Sopenharmony_ci mlxsw_reg_slcor_col_enable_pack(slcor_pl, mlxsw_sp_port->local_port, 34728c2ecf20Sopenharmony_ci lag_id); 34738c2ecf20Sopenharmony_ci return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(slcor), slcor_pl); 34748c2ecf20Sopenharmony_ci} 34758c2ecf20Sopenharmony_ci 34768c2ecf20Sopenharmony_cistatic int mlxsw_sp_lag_col_port_disable(struct mlxsw_sp_port *mlxsw_sp_port, 34778c2ecf20Sopenharmony_ci u16 lag_id) 34788c2ecf20Sopenharmony_ci{ 34798c2ecf20Sopenharmony_ci struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; 34808c2ecf20Sopenharmony_ci char slcor_pl[MLXSW_REG_SLCOR_LEN]; 34818c2ecf20Sopenharmony_ci 34828c2ecf20Sopenharmony_ci mlxsw_reg_slcor_col_disable_pack(slcor_pl, mlxsw_sp_port->local_port, 34838c2ecf20Sopenharmony_ci lag_id); 34848c2ecf20Sopenharmony_ci return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(slcor), slcor_pl); 34858c2ecf20Sopenharmony_ci} 34868c2ecf20Sopenharmony_ci 34878c2ecf20Sopenharmony_cistatic int mlxsw_sp_lag_index_get(struct mlxsw_sp *mlxsw_sp, 34888c2ecf20Sopenharmony_ci struct net_device *lag_dev, 34898c2ecf20Sopenharmony_ci u16 *p_lag_id) 34908c2ecf20Sopenharmony_ci{ 34918c2ecf20Sopenharmony_ci struct mlxsw_sp_upper *lag; 34928c2ecf20Sopenharmony_ci int free_lag_id = -1; 34938c2ecf20Sopenharmony_ci u64 max_lag; 34948c2ecf20Sopenharmony_ci int i; 34958c2ecf20Sopenharmony_ci 34968c2ecf20Sopenharmony_ci max_lag = MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_LAG); 34978c2ecf20Sopenharmony_ci for (i = 0; i < max_lag; i++) { 34988c2ecf20Sopenharmony_ci lag = mlxsw_sp_lag_get(mlxsw_sp, i); 34998c2ecf20Sopenharmony_ci if (lag->ref_count) { 35008c2ecf20Sopenharmony_ci if (lag->dev == lag_dev) { 35018c2ecf20Sopenharmony_ci *p_lag_id = i; 35028c2ecf20Sopenharmony_ci return 0; 35038c2ecf20Sopenharmony_ci } 35048c2ecf20Sopenharmony_ci } else if (free_lag_id < 0) { 35058c2ecf20Sopenharmony_ci free_lag_id = i; 35068c2ecf20Sopenharmony_ci } 35078c2ecf20Sopenharmony_ci } 35088c2ecf20Sopenharmony_ci if (free_lag_id < 0) 35098c2ecf20Sopenharmony_ci return -EBUSY; 35108c2ecf20Sopenharmony_ci *p_lag_id = free_lag_id; 35118c2ecf20Sopenharmony_ci return 0; 35128c2ecf20Sopenharmony_ci} 35138c2ecf20Sopenharmony_ci 35148c2ecf20Sopenharmony_cistatic bool 35158c2ecf20Sopenharmony_cimlxsw_sp_master_lag_check(struct mlxsw_sp *mlxsw_sp, 35168c2ecf20Sopenharmony_ci struct net_device *lag_dev, 35178c2ecf20Sopenharmony_ci struct netdev_lag_upper_info *lag_upper_info, 35188c2ecf20Sopenharmony_ci struct netlink_ext_ack *extack) 35198c2ecf20Sopenharmony_ci{ 35208c2ecf20Sopenharmony_ci u16 lag_id; 35218c2ecf20Sopenharmony_ci 35228c2ecf20Sopenharmony_ci if (mlxsw_sp_lag_index_get(mlxsw_sp, lag_dev, &lag_id) != 0) { 35238c2ecf20Sopenharmony_ci NL_SET_ERR_MSG_MOD(extack, "Exceeded number of supported LAG devices"); 35248c2ecf20Sopenharmony_ci return false; 35258c2ecf20Sopenharmony_ci } 35268c2ecf20Sopenharmony_ci if (lag_upper_info->tx_type != NETDEV_LAG_TX_TYPE_HASH) { 35278c2ecf20Sopenharmony_ci NL_SET_ERR_MSG_MOD(extack, "LAG device using unsupported Tx type"); 35288c2ecf20Sopenharmony_ci return false; 35298c2ecf20Sopenharmony_ci } 35308c2ecf20Sopenharmony_ci return true; 35318c2ecf20Sopenharmony_ci} 35328c2ecf20Sopenharmony_ci 35338c2ecf20Sopenharmony_cistatic int mlxsw_sp_port_lag_index_get(struct mlxsw_sp *mlxsw_sp, 35348c2ecf20Sopenharmony_ci u16 lag_id, u8 *p_port_index) 35358c2ecf20Sopenharmony_ci{ 35368c2ecf20Sopenharmony_ci u64 max_lag_members; 35378c2ecf20Sopenharmony_ci int i; 35388c2ecf20Sopenharmony_ci 35398c2ecf20Sopenharmony_ci max_lag_members = MLXSW_CORE_RES_GET(mlxsw_sp->core, 35408c2ecf20Sopenharmony_ci MAX_LAG_MEMBERS); 35418c2ecf20Sopenharmony_ci for (i = 0; i < max_lag_members; i++) { 35428c2ecf20Sopenharmony_ci if (!mlxsw_sp_port_lagged_get(mlxsw_sp, lag_id, i)) { 35438c2ecf20Sopenharmony_ci *p_port_index = i; 35448c2ecf20Sopenharmony_ci return 0; 35458c2ecf20Sopenharmony_ci } 35468c2ecf20Sopenharmony_ci } 35478c2ecf20Sopenharmony_ci return -EBUSY; 35488c2ecf20Sopenharmony_ci} 35498c2ecf20Sopenharmony_ci 35508c2ecf20Sopenharmony_cistatic int mlxsw_sp_port_lag_join(struct mlxsw_sp_port *mlxsw_sp_port, 35518c2ecf20Sopenharmony_ci struct net_device *lag_dev) 35528c2ecf20Sopenharmony_ci{ 35538c2ecf20Sopenharmony_ci struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; 35548c2ecf20Sopenharmony_ci struct mlxsw_sp_upper *lag; 35558c2ecf20Sopenharmony_ci u16 lag_id; 35568c2ecf20Sopenharmony_ci u8 port_index; 35578c2ecf20Sopenharmony_ci int err; 35588c2ecf20Sopenharmony_ci 35598c2ecf20Sopenharmony_ci err = mlxsw_sp_lag_index_get(mlxsw_sp, lag_dev, &lag_id); 35608c2ecf20Sopenharmony_ci if (err) 35618c2ecf20Sopenharmony_ci return err; 35628c2ecf20Sopenharmony_ci lag = mlxsw_sp_lag_get(mlxsw_sp, lag_id); 35638c2ecf20Sopenharmony_ci if (!lag->ref_count) { 35648c2ecf20Sopenharmony_ci err = mlxsw_sp_lag_create(mlxsw_sp, lag_id); 35658c2ecf20Sopenharmony_ci if (err) 35668c2ecf20Sopenharmony_ci return err; 35678c2ecf20Sopenharmony_ci lag->dev = lag_dev; 35688c2ecf20Sopenharmony_ci } 35698c2ecf20Sopenharmony_ci 35708c2ecf20Sopenharmony_ci err = mlxsw_sp_port_lag_index_get(mlxsw_sp, lag_id, &port_index); 35718c2ecf20Sopenharmony_ci if (err) 35728c2ecf20Sopenharmony_ci return err; 35738c2ecf20Sopenharmony_ci err = mlxsw_sp_lag_col_port_add(mlxsw_sp_port, lag_id, port_index); 35748c2ecf20Sopenharmony_ci if (err) 35758c2ecf20Sopenharmony_ci goto err_col_port_add; 35768c2ecf20Sopenharmony_ci 35778c2ecf20Sopenharmony_ci mlxsw_core_lag_mapping_set(mlxsw_sp->core, lag_id, port_index, 35788c2ecf20Sopenharmony_ci mlxsw_sp_port->local_port); 35798c2ecf20Sopenharmony_ci mlxsw_sp_port->lag_id = lag_id; 35808c2ecf20Sopenharmony_ci mlxsw_sp_port->lagged = 1; 35818c2ecf20Sopenharmony_ci lag->ref_count++; 35828c2ecf20Sopenharmony_ci 35838c2ecf20Sopenharmony_ci /* Port is no longer usable as a router interface */ 35848c2ecf20Sopenharmony_ci if (mlxsw_sp_port->default_vlan->fid) 35858c2ecf20Sopenharmony_ci mlxsw_sp_port_vlan_router_leave(mlxsw_sp_port->default_vlan); 35868c2ecf20Sopenharmony_ci 35878c2ecf20Sopenharmony_ci return 0; 35888c2ecf20Sopenharmony_ci 35898c2ecf20Sopenharmony_cierr_col_port_add: 35908c2ecf20Sopenharmony_ci if (!lag->ref_count) 35918c2ecf20Sopenharmony_ci mlxsw_sp_lag_destroy(mlxsw_sp, lag_id); 35928c2ecf20Sopenharmony_ci return err; 35938c2ecf20Sopenharmony_ci} 35948c2ecf20Sopenharmony_ci 35958c2ecf20Sopenharmony_cistatic void mlxsw_sp_port_lag_leave(struct mlxsw_sp_port *mlxsw_sp_port, 35968c2ecf20Sopenharmony_ci struct net_device *lag_dev) 35978c2ecf20Sopenharmony_ci{ 35988c2ecf20Sopenharmony_ci struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; 35998c2ecf20Sopenharmony_ci u16 lag_id = mlxsw_sp_port->lag_id; 36008c2ecf20Sopenharmony_ci struct mlxsw_sp_upper *lag; 36018c2ecf20Sopenharmony_ci 36028c2ecf20Sopenharmony_ci if (!mlxsw_sp_port->lagged) 36038c2ecf20Sopenharmony_ci return; 36048c2ecf20Sopenharmony_ci lag = mlxsw_sp_lag_get(mlxsw_sp, lag_id); 36058c2ecf20Sopenharmony_ci WARN_ON(lag->ref_count == 0); 36068c2ecf20Sopenharmony_ci 36078c2ecf20Sopenharmony_ci mlxsw_sp_lag_col_port_remove(mlxsw_sp_port, lag_id); 36088c2ecf20Sopenharmony_ci 36098c2ecf20Sopenharmony_ci /* Any VLANs configured on the port are no longer valid */ 36108c2ecf20Sopenharmony_ci mlxsw_sp_port_vlan_flush(mlxsw_sp_port, false); 36118c2ecf20Sopenharmony_ci mlxsw_sp_port_vlan_cleanup(mlxsw_sp_port->default_vlan); 36128c2ecf20Sopenharmony_ci /* Make the LAG and its directly linked uppers leave bridges they 36138c2ecf20Sopenharmony_ci * are memeber in 36148c2ecf20Sopenharmony_ci */ 36158c2ecf20Sopenharmony_ci mlxsw_sp_port_lag_uppers_cleanup(mlxsw_sp_port, lag_dev); 36168c2ecf20Sopenharmony_ci 36178c2ecf20Sopenharmony_ci if (lag->ref_count == 1) 36188c2ecf20Sopenharmony_ci mlxsw_sp_lag_destroy(mlxsw_sp, lag_id); 36198c2ecf20Sopenharmony_ci 36208c2ecf20Sopenharmony_ci mlxsw_core_lag_mapping_clear(mlxsw_sp->core, lag_id, 36218c2ecf20Sopenharmony_ci mlxsw_sp_port->local_port); 36228c2ecf20Sopenharmony_ci mlxsw_sp_port->lagged = 0; 36238c2ecf20Sopenharmony_ci lag->ref_count--; 36248c2ecf20Sopenharmony_ci 36258c2ecf20Sopenharmony_ci /* Make sure untagged frames are allowed to ingress */ 36268c2ecf20Sopenharmony_ci mlxsw_sp_port_pvid_set(mlxsw_sp_port, MLXSW_SP_DEFAULT_VID); 36278c2ecf20Sopenharmony_ci} 36288c2ecf20Sopenharmony_ci 36298c2ecf20Sopenharmony_cistatic int mlxsw_sp_lag_dist_port_add(struct mlxsw_sp_port *mlxsw_sp_port, 36308c2ecf20Sopenharmony_ci u16 lag_id) 36318c2ecf20Sopenharmony_ci{ 36328c2ecf20Sopenharmony_ci struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; 36338c2ecf20Sopenharmony_ci char sldr_pl[MLXSW_REG_SLDR_LEN]; 36348c2ecf20Sopenharmony_ci 36358c2ecf20Sopenharmony_ci mlxsw_reg_sldr_lag_add_port_pack(sldr_pl, lag_id, 36368c2ecf20Sopenharmony_ci mlxsw_sp_port->local_port); 36378c2ecf20Sopenharmony_ci return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(sldr), sldr_pl); 36388c2ecf20Sopenharmony_ci} 36398c2ecf20Sopenharmony_ci 36408c2ecf20Sopenharmony_cistatic int mlxsw_sp_lag_dist_port_remove(struct mlxsw_sp_port *mlxsw_sp_port, 36418c2ecf20Sopenharmony_ci u16 lag_id) 36428c2ecf20Sopenharmony_ci{ 36438c2ecf20Sopenharmony_ci struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; 36448c2ecf20Sopenharmony_ci char sldr_pl[MLXSW_REG_SLDR_LEN]; 36458c2ecf20Sopenharmony_ci 36468c2ecf20Sopenharmony_ci mlxsw_reg_sldr_lag_remove_port_pack(sldr_pl, lag_id, 36478c2ecf20Sopenharmony_ci mlxsw_sp_port->local_port); 36488c2ecf20Sopenharmony_ci return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(sldr), sldr_pl); 36498c2ecf20Sopenharmony_ci} 36508c2ecf20Sopenharmony_ci 36518c2ecf20Sopenharmony_cistatic int 36528c2ecf20Sopenharmony_cimlxsw_sp_port_lag_col_dist_enable(struct mlxsw_sp_port *mlxsw_sp_port) 36538c2ecf20Sopenharmony_ci{ 36548c2ecf20Sopenharmony_ci int err; 36558c2ecf20Sopenharmony_ci 36568c2ecf20Sopenharmony_ci err = mlxsw_sp_lag_col_port_enable(mlxsw_sp_port, 36578c2ecf20Sopenharmony_ci mlxsw_sp_port->lag_id); 36588c2ecf20Sopenharmony_ci if (err) 36598c2ecf20Sopenharmony_ci return err; 36608c2ecf20Sopenharmony_ci 36618c2ecf20Sopenharmony_ci err = mlxsw_sp_lag_dist_port_add(mlxsw_sp_port, mlxsw_sp_port->lag_id); 36628c2ecf20Sopenharmony_ci if (err) 36638c2ecf20Sopenharmony_ci goto err_dist_port_add; 36648c2ecf20Sopenharmony_ci 36658c2ecf20Sopenharmony_ci return 0; 36668c2ecf20Sopenharmony_ci 36678c2ecf20Sopenharmony_cierr_dist_port_add: 36688c2ecf20Sopenharmony_ci mlxsw_sp_lag_col_port_disable(mlxsw_sp_port, mlxsw_sp_port->lag_id); 36698c2ecf20Sopenharmony_ci return err; 36708c2ecf20Sopenharmony_ci} 36718c2ecf20Sopenharmony_ci 36728c2ecf20Sopenharmony_cistatic int 36738c2ecf20Sopenharmony_cimlxsw_sp_port_lag_col_dist_disable(struct mlxsw_sp_port *mlxsw_sp_port) 36748c2ecf20Sopenharmony_ci{ 36758c2ecf20Sopenharmony_ci int err; 36768c2ecf20Sopenharmony_ci 36778c2ecf20Sopenharmony_ci err = mlxsw_sp_lag_dist_port_remove(mlxsw_sp_port, 36788c2ecf20Sopenharmony_ci mlxsw_sp_port->lag_id); 36798c2ecf20Sopenharmony_ci if (err) 36808c2ecf20Sopenharmony_ci return err; 36818c2ecf20Sopenharmony_ci 36828c2ecf20Sopenharmony_ci err = mlxsw_sp_lag_col_port_disable(mlxsw_sp_port, 36838c2ecf20Sopenharmony_ci mlxsw_sp_port->lag_id); 36848c2ecf20Sopenharmony_ci if (err) 36858c2ecf20Sopenharmony_ci goto err_col_port_disable; 36868c2ecf20Sopenharmony_ci 36878c2ecf20Sopenharmony_ci return 0; 36888c2ecf20Sopenharmony_ci 36898c2ecf20Sopenharmony_cierr_col_port_disable: 36908c2ecf20Sopenharmony_ci mlxsw_sp_lag_dist_port_add(mlxsw_sp_port, mlxsw_sp_port->lag_id); 36918c2ecf20Sopenharmony_ci return err; 36928c2ecf20Sopenharmony_ci} 36938c2ecf20Sopenharmony_ci 36948c2ecf20Sopenharmony_cistatic int mlxsw_sp_port_lag_changed(struct mlxsw_sp_port *mlxsw_sp_port, 36958c2ecf20Sopenharmony_ci struct netdev_lag_lower_state_info *info) 36968c2ecf20Sopenharmony_ci{ 36978c2ecf20Sopenharmony_ci if (info->tx_enabled) 36988c2ecf20Sopenharmony_ci return mlxsw_sp_port_lag_col_dist_enable(mlxsw_sp_port); 36998c2ecf20Sopenharmony_ci else 37008c2ecf20Sopenharmony_ci return mlxsw_sp_port_lag_col_dist_disable(mlxsw_sp_port); 37018c2ecf20Sopenharmony_ci} 37028c2ecf20Sopenharmony_ci 37038c2ecf20Sopenharmony_cistatic int mlxsw_sp_port_stp_set(struct mlxsw_sp_port *mlxsw_sp_port, 37048c2ecf20Sopenharmony_ci bool enable) 37058c2ecf20Sopenharmony_ci{ 37068c2ecf20Sopenharmony_ci struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; 37078c2ecf20Sopenharmony_ci enum mlxsw_reg_spms_state spms_state; 37088c2ecf20Sopenharmony_ci char *spms_pl; 37098c2ecf20Sopenharmony_ci u16 vid; 37108c2ecf20Sopenharmony_ci int err; 37118c2ecf20Sopenharmony_ci 37128c2ecf20Sopenharmony_ci spms_state = enable ? MLXSW_REG_SPMS_STATE_FORWARDING : 37138c2ecf20Sopenharmony_ci MLXSW_REG_SPMS_STATE_DISCARDING; 37148c2ecf20Sopenharmony_ci 37158c2ecf20Sopenharmony_ci spms_pl = kmalloc(MLXSW_REG_SPMS_LEN, GFP_KERNEL); 37168c2ecf20Sopenharmony_ci if (!spms_pl) 37178c2ecf20Sopenharmony_ci return -ENOMEM; 37188c2ecf20Sopenharmony_ci mlxsw_reg_spms_pack(spms_pl, mlxsw_sp_port->local_port); 37198c2ecf20Sopenharmony_ci 37208c2ecf20Sopenharmony_ci for (vid = 0; vid < VLAN_N_VID; vid++) 37218c2ecf20Sopenharmony_ci mlxsw_reg_spms_vid_pack(spms_pl, vid, spms_state); 37228c2ecf20Sopenharmony_ci 37238c2ecf20Sopenharmony_ci err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(spms), spms_pl); 37248c2ecf20Sopenharmony_ci kfree(spms_pl); 37258c2ecf20Sopenharmony_ci return err; 37268c2ecf20Sopenharmony_ci} 37278c2ecf20Sopenharmony_ci 37288c2ecf20Sopenharmony_cistatic int mlxsw_sp_port_ovs_join(struct mlxsw_sp_port *mlxsw_sp_port) 37298c2ecf20Sopenharmony_ci{ 37308c2ecf20Sopenharmony_ci u16 vid = 1; 37318c2ecf20Sopenharmony_ci int err; 37328c2ecf20Sopenharmony_ci 37338c2ecf20Sopenharmony_ci err = mlxsw_sp_port_vp_mode_set(mlxsw_sp_port, true); 37348c2ecf20Sopenharmony_ci if (err) 37358c2ecf20Sopenharmony_ci return err; 37368c2ecf20Sopenharmony_ci err = mlxsw_sp_port_stp_set(mlxsw_sp_port, true); 37378c2ecf20Sopenharmony_ci if (err) 37388c2ecf20Sopenharmony_ci goto err_port_stp_set; 37398c2ecf20Sopenharmony_ci err = mlxsw_sp_port_vlan_set(mlxsw_sp_port, 1, VLAN_N_VID - 2, 37408c2ecf20Sopenharmony_ci true, false); 37418c2ecf20Sopenharmony_ci if (err) 37428c2ecf20Sopenharmony_ci goto err_port_vlan_set; 37438c2ecf20Sopenharmony_ci 37448c2ecf20Sopenharmony_ci for (; vid <= VLAN_N_VID - 1; vid++) { 37458c2ecf20Sopenharmony_ci err = mlxsw_sp_port_vid_learning_set(mlxsw_sp_port, 37468c2ecf20Sopenharmony_ci vid, false); 37478c2ecf20Sopenharmony_ci if (err) 37488c2ecf20Sopenharmony_ci goto err_vid_learning_set; 37498c2ecf20Sopenharmony_ci } 37508c2ecf20Sopenharmony_ci 37518c2ecf20Sopenharmony_ci return 0; 37528c2ecf20Sopenharmony_ci 37538c2ecf20Sopenharmony_cierr_vid_learning_set: 37548c2ecf20Sopenharmony_ci for (vid--; vid >= 1; vid--) 37558c2ecf20Sopenharmony_ci mlxsw_sp_port_vid_learning_set(mlxsw_sp_port, vid, true); 37568c2ecf20Sopenharmony_cierr_port_vlan_set: 37578c2ecf20Sopenharmony_ci mlxsw_sp_port_stp_set(mlxsw_sp_port, false); 37588c2ecf20Sopenharmony_cierr_port_stp_set: 37598c2ecf20Sopenharmony_ci mlxsw_sp_port_vp_mode_set(mlxsw_sp_port, false); 37608c2ecf20Sopenharmony_ci return err; 37618c2ecf20Sopenharmony_ci} 37628c2ecf20Sopenharmony_ci 37638c2ecf20Sopenharmony_cistatic void mlxsw_sp_port_ovs_leave(struct mlxsw_sp_port *mlxsw_sp_port) 37648c2ecf20Sopenharmony_ci{ 37658c2ecf20Sopenharmony_ci u16 vid; 37668c2ecf20Sopenharmony_ci 37678c2ecf20Sopenharmony_ci for (vid = VLAN_N_VID - 1; vid >= 1; vid--) 37688c2ecf20Sopenharmony_ci mlxsw_sp_port_vid_learning_set(mlxsw_sp_port, 37698c2ecf20Sopenharmony_ci vid, true); 37708c2ecf20Sopenharmony_ci 37718c2ecf20Sopenharmony_ci mlxsw_sp_port_vlan_set(mlxsw_sp_port, 1, VLAN_N_VID - 2, 37728c2ecf20Sopenharmony_ci false, false); 37738c2ecf20Sopenharmony_ci mlxsw_sp_port_stp_set(mlxsw_sp_port, false); 37748c2ecf20Sopenharmony_ci mlxsw_sp_port_vp_mode_set(mlxsw_sp_port, false); 37758c2ecf20Sopenharmony_ci} 37768c2ecf20Sopenharmony_ci 37778c2ecf20Sopenharmony_cistatic bool mlxsw_sp_bridge_has_multiple_vxlans(struct net_device *br_dev) 37788c2ecf20Sopenharmony_ci{ 37798c2ecf20Sopenharmony_ci unsigned int num_vxlans = 0; 37808c2ecf20Sopenharmony_ci struct net_device *dev; 37818c2ecf20Sopenharmony_ci struct list_head *iter; 37828c2ecf20Sopenharmony_ci 37838c2ecf20Sopenharmony_ci netdev_for_each_lower_dev(br_dev, dev, iter) { 37848c2ecf20Sopenharmony_ci if (netif_is_vxlan(dev)) 37858c2ecf20Sopenharmony_ci num_vxlans++; 37868c2ecf20Sopenharmony_ci } 37878c2ecf20Sopenharmony_ci 37888c2ecf20Sopenharmony_ci return num_vxlans > 1; 37898c2ecf20Sopenharmony_ci} 37908c2ecf20Sopenharmony_ci 37918c2ecf20Sopenharmony_cistatic bool mlxsw_sp_bridge_vxlan_vlan_is_valid(struct net_device *br_dev) 37928c2ecf20Sopenharmony_ci{ 37938c2ecf20Sopenharmony_ci DECLARE_BITMAP(vlans, VLAN_N_VID) = {0}; 37948c2ecf20Sopenharmony_ci struct net_device *dev; 37958c2ecf20Sopenharmony_ci struct list_head *iter; 37968c2ecf20Sopenharmony_ci 37978c2ecf20Sopenharmony_ci netdev_for_each_lower_dev(br_dev, dev, iter) { 37988c2ecf20Sopenharmony_ci u16 pvid; 37998c2ecf20Sopenharmony_ci int err; 38008c2ecf20Sopenharmony_ci 38018c2ecf20Sopenharmony_ci if (!netif_is_vxlan(dev)) 38028c2ecf20Sopenharmony_ci continue; 38038c2ecf20Sopenharmony_ci 38048c2ecf20Sopenharmony_ci err = mlxsw_sp_vxlan_mapped_vid(dev, &pvid); 38058c2ecf20Sopenharmony_ci if (err || !pvid) 38068c2ecf20Sopenharmony_ci continue; 38078c2ecf20Sopenharmony_ci 38088c2ecf20Sopenharmony_ci if (test_and_set_bit(pvid, vlans)) 38098c2ecf20Sopenharmony_ci return false; 38108c2ecf20Sopenharmony_ci } 38118c2ecf20Sopenharmony_ci 38128c2ecf20Sopenharmony_ci return true; 38138c2ecf20Sopenharmony_ci} 38148c2ecf20Sopenharmony_ci 38158c2ecf20Sopenharmony_cistatic bool mlxsw_sp_bridge_vxlan_is_valid(struct net_device *br_dev, 38168c2ecf20Sopenharmony_ci struct netlink_ext_ack *extack) 38178c2ecf20Sopenharmony_ci{ 38188c2ecf20Sopenharmony_ci if (br_multicast_enabled(br_dev)) { 38198c2ecf20Sopenharmony_ci NL_SET_ERR_MSG_MOD(extack, "Multicast can not be enabled on a bridge with a VxLAN device"); 38208c2ecf20Sopenharmony_ci return false; 38218c2ecf20Sopenharmony_ci } 38228c2ecf20Sopenharmony_ci 38238c2ecf20Sopenharmony_ci if (!br_vlan_enabled(br_dev) && 38248c2ecf20Sopenharmony_ci mlxsw_sp_bridge_has_multiple_vxlans(br_dev)) { 38258c2ecf20Sopenharmony_ci NL_SET_ERR_MSG_MOD(extack, "Multiple VxLAN devices are not supported in a VLAN-unaware bridge"); 38268c2ecf20Sopenharmony_ci return false; 38278c2ecf20Sopenharmony_ci } 38288c2ecf20Sopenharmony_ci 38298c2ecf20Sopenharmony_ci if (br_vlan_enabled(br_dev) && 38308c2ecf20Sopenharmony_ci !mlxsw_sp_bridge_vxlan_vlan_is_valid(br_dev)) { 38318c2ecf20Sopenharmony_ci NL_SET_ERR_MSG_MOD(extack, "Multiple VxLAN devices cannot have the same VLAN as PVID and egress untagged"); 38328c2ecf20Sopenharmony_ci return false; 38338c2ecf20Sopenharmony_ci } 38348c2ecf20Sopenharmony_ci 38358c2ecf20Sopenharmony_ci return true; 38368c2ecf20Sopenharmony_ci} 38378c2ecf20Sopenharmony_ci 38388c2ecf20Sopenharmony_cistatic int mlxsw_sp_netdevice_port_upper_event(struct net_device *lower_dev, 38398c2ecf20Sopenharmony_ci struct net_device *dev, 38408c2ecf20Sopenharmony_ci unsigned long event, void *ptr) 38418c2ecf20Sopenharmony_ci{ 38428c2ecf20Sopenharmony_ci struct netdev_notifier_changeupper_info *info; 38438c2ecf20Sopenharmony_ci struct mlxsw_sp_port *mlxsw_sp_port; 38448c2ecf20Sopenharmony_ci struct netlink_ext_ack *extack; 38458c2ecf20Sopenharmony_ci struct net_device *upper_dev; 38468c2ecf20Sopenharmony_ci struct mlxsw_sp *mlxsw_sp; 38478c2ecf20Sopenharmony_ci int err = 0; 38488c2ecf20Sopenharmony_ci 38498c2ecf20Sopenharmony_ci mlxsw_sp_port = netdev_priv(dev); 38508c2ecf20Sopenharmony_ci mlxsw_sp = mlxsw_sp_port->mlxsw_sp; 38518c2ecf20Sopenharmony_ci info = ptr; 38528c2ecf20Sopenharmony_ci extack = netdev_notifier_info_to_extack(&info->info); 38538c2ecf20Sopenharmony_ci 38548c2ecf20Sopenharmony_ci switch (event) { 38558c2ecf20Sopenharmony_ci case NETDEV_PRECHANGEUPPER: 38568c2ecf20Sopenharmony_ci upper_dev = info->upper_dev; 38578c2ecf20Sopenharmony_ci if (!is_vlan_dev(upper_dev) && 38588c2ecf20Sopenharmony_ci !netif_is_lag_master(upper_dev) && 38598c2ecf20Sopenharmony_ci !netif_is_bridge_master(upper_dev) && 38608c2ecf20Sopenharmony_ci !netif_is_ovs_master(upper_dev) && 38618c2ecf20Sopenharmony_ci !netif_is_macvlan(upper_dev)) { 38628c2ecf20Sopenharmony_ci NL_SET_ERR_MSG_MOD(extack, "Unknown upper device type"); 38638c2ecf20Sopenharmony_ci return -EINVAL; 38648c2ecf20Sopenharmony_ci } 38658c2ecf20Sopenharmony_ci if (!info->linking) 38668c2ecf20Sopenharmony_ci break; 38678c2ecf20Sopenharmony_ci if (netif_is_bridge_master(upper_dev) && 38688c2ecf20Sopenharmony_ci !mlxsw_sp_bridge_device_is_offloaded(mlxsw_sp, upper_dev) && 38698c2ecf20Sopenharmony_ci mlxsw_sp_bridge_has_vxlan(upper_dev) && 38708c2ecf20Sopenharmony_ci !mlxsw_sp_bridge_vxlan_is_valid(upper_dev, extack)) 38718c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 38728c2ecf20Sopenharmony_ci if (netdev_has_any_upper_dev(upper_dev) && 38738c2ecf20Sopenharmony_ci (!netif_is_bridge_master(upper_dev) || 38748c2ecf20Sopenharmony_ci !mlxsw_sp_bridge_device_is_offloaded(mlxsw_sp, 38758c2ecf20Sopenharmony_ci upper_dev))) { 38768c2ecf20Sopenharmony_ci NL_SET_ERR_MSG_MOD(extack, "Enslaving a port to a device that already has an upper device is not supported"); 38778c2ecf20Sopenharmony_ci return -EINVAL; 38788c2ecf20Sopenharmony_ci } 38798c2ecf20Sopenharmony_ci if (netif_is_lag_master(upper_dev) && 38808c2ecf20Sopenharmony_ci !mlxsw_sp_master_lag_check(mlxsw_sp, upper_dev, 38818c2ecf20Sopenharmony_ci info->upper_info, extack)) 38828c2ecf20Sopenharmony_ci return -EINVAL; 38838c2ecf20Sopenharmony_ci if (netif_is_lag_master(upper_dev) && vlan_uses_dev(dev)) { 38848c2ecf20Sopenharmony_ci NL_SET_ERR_MSG_MOD(extack, "Master device is a LAG master and this device has a VLAN"); 38858c2ecf20Sopenharmony_ci return -EINVAL; 38868c2ecf20Sopenharmony_ci } 38878c2ecf20Sopenharmony_ci if (netif_is_lag_port(dev) && is_vlan_dev(upper_dev) && 38888c2ecf20Sopenharmony_ci !netif_is_lag_master(vlan_dev_real_dev(upper_dev))) { 38898c2ecf20Sopenharmony_ci NL_SET_ERR_MSG_MOD(extack, "Can not put a VLAN on a LAG port"); 38908c2ecf20Sopenharmony_ci return -EINVAL; 38918c2ecf20Sopenharmony_ci } 38928c2ecf20Sopenharmony_ci if (netif_is_macvlan(upper_dev) && 38938c2ecf20Sopenharmony_ci !mlxsw_sp_rif_exists(mlxsw_sp, lower_dev)) { 38948c2ecf20Sopenharmony_ci NL_SET_ERR_MSG_MOD(extack, "macvlan is only supported on top of router interfaces"); 38958c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 38968c2ecf20Sopenharmony_ci } 38978c2ecf20Sopenharmony_ci if (netif_is_ovs_master(upper_dev) && vlan_uses_dev(dev)) { 38988c2ecf20Sopenharmony_ci NL_SET_ERR_MSG_MOD(extack, "Master device is an OVS master and this device has a VLAN"); 38998c2ecf20Sopenharmony_ci return -EINVAL; 39008c2ecf20Sopenharmony_ci } 39018c2ecf20Sopenharmony_ci if (netif_is_ovs_port(dev) && is_vlan_dev(upper_dev)) { 39028c2ecf20Sopenharmony_ci NL_SET_ERR_MSG_MOD(extack, "Can not put a VLAN on an OVS port"); 39038c2ecf20Sopenharmony_ci return -EINVAL; 39048c2ecf20Sopenharmony_ci } 39058c2ecf20Sopenharmony_ci break; 39068c2ecf20Sopenharmony_ci case NETDEV_CHANGEUPPER: 39078c2ecf20Sopenharmony_ci upper_dev = info->upper_dev; 39088c2ecf20Sopenharmony_ci if (netif_is_bridge_master(upper_dev)) { 39098c2ecf20Sopenharmony_ci if (info->linking) 39108c2ecf20Sopenharmony_ci err = mlxsw_sp_port_bridge_join(mlxsw_sp_port, 39118c2ecf20Sopenharmony_ci lower_dev, 39128c2ecf20Sopenharmony_ci upper_dev, 39138c2ecf20Sopenharmony_ci extack); 39148c2ecf20Sopenharmony_ci else 39158c2ecf20Sopenharmony_ci mlxsw_sp_port_bridge_leave(mlxsw_sp_port, 39168c2ecf20Sopenharmony_ci lower_dev, 39178c2ecf20Sopenharmony_ci upper_dev); 39188c2ecf20Sopenharmony_ci } else if (netif_is_lag_master(upper_dev)) { 39198c2ecf20Sopenharmony_ci if (info->linking) { 39208c2ecf20Sopenharmony_ci err = mlxsw_sp_port_lag_join(mlxsw_sp_port, 39218c2ecf20Sopenharmony_ci upper_dev); 39228c2ecf20Sopenharmony_ci } else { 39238c2ecf20Sopenharmony_ci mlxsw_sp_port_lag_col_dist_disable(mlxsw_sp_port); 39248c2ecf20Sopenharmony_ci mlxsw_sp_port_lag_leave(mlxsw_sp_port, 39258c2ecf20Sopenharmony_ci upper_dev); 39268c2ecf20Sopenharmony_ci } 39278c2ecf20Sopenharmony_ci } else if (netif_is_ovs_master(upper_dev)) { 39288c2ecf20Sopenharmony_ci if (info->linking) 39298c2ecf20Sopenharmony_ci err = mlxsw_sp_port_ovs_join(mlxsw_sp_port); 39308c2ecf20Sopenharmony_ci else 39318c2ecf20Sopenharmony_ci mlxsw_sp_port_ovs_leave(mlxsw_sp_port); 39328c2ecf20Sopenharmony_ci } else if (netif_is_macvlan(upper_dev)) { 39338c2ecf20Sopenharmony_ci if (!info->linking) 39348c2ecf20Sopenharmony_ci mlxsw_sp_rif_macvlan_del(mlxsw_sp, upper_dev); 39358c2ecf20Sopenharmony_ci } else if (is_vlan_dev(upper_dev)) { 39368c2ecf20Sopenharmony_ci struct net_device *br_dev; 39378c2ecf20Sopenharmony_ci 39388c2ecf20Sopenharmony_ci if (!netif_is_bridge_port(upper_dev)) 39398c2ecf20Sopenharmony_ci break; 39408c2ecf20Sopenharmony_ci if (info->linking) 39418c2ecf20Sopenharmony_ci break; 39428c2ecf20Sopenharmony_ci br_dev = netdev_master_upper_dev_get(upper_dev); 39438c2ecf20Sopenharmony_ci mlxsw_sp_port_bridge_leave(mlxsw_sp_port, upper_dev, 39448c2ecf20Sopenharmony_ci br_dev); 39458c2ecf20Sopenharmony_ci } 39468c2ecf20Sopenharmony_ci break; 39478c2ecf20Sopenharmony_ci } 39488c2ecf20Sopenharmony_ci 39498c2ecf20Sopenharmony_ci return err; 39508c2ecf20Sopenharmony_ci} 39518c2ecf20Sopenharmony_ci 39528c2ecf20Sopenharmony_cistatic int mlxsw_sp_netdevice_port_lower_event(struct net_device *dev, 39538c2ecf20Sopenharmony_ci unsigned long event, void *ptr) 39548c2ecf20Sopenharmony_ci{ 39558c2ecf20Sopenharmony_ci struct netdev_notifier_changelowerstate_info *info; 39568c2ecf20Sopenharmony_ci struct mlxsw_sp_port *mlxsw_sp_port; 39578c2ecf20Sopenharmony_ci int err; 39588c2ecf20Sopenharmony_ci 39598c2ecf20Sopenharmony_ci mlxsw_sp_port = netdev_priv(dev); 39608c2ecf20Sopenharmony_ci info = ptr; 39618c2ecf20Sopenharmony_ci 39628c2ecf20Sopenharmony_ci switch (event) { 39638c2ecf20Sopenharmony_ci case NETDEV_CHANGELOWERSTATE: 39648c2ecf20Sopenharmony_ci if (netif_is_lag_port(dev) && mlxsw_sp_port->lagged) { 39658c2ecf20Sopenharmony_ci err = mlxsw_sp_port_lag_changed(mlxsw_sp_port, 39668c2ecf20Sopenharmony_ci info->lower_state_info); 39678c2ecf20Sopenharmony_ci if (err) 39688c2ecf20Sopenharmony_ci netdev_err(dev, "Failed to reflect link aggregation lower state change\n"); 39698c2ecf20Sopenharmony_ci } 39708c2ecf20Sopenharmony_ci break; 39718c2ecf20Sopenharmony_ci } 39728c2ecf20Sopenharmony_ci 39738c2ecf20Sopenharmony_ci return 0; 39748c2ecf20Sopenharmony_ci} 39758c2ecf20Sopenharmony_ci 39768c2ecf20Sopenharmony_cistatic int mlxsw_sp_netdevice_port_event(struct net_device *lower_dev, 39778c2ecf20Sopenharmony_ci struct net_device *port_dev, 39788c2ecf20Sopenharmony_ci unsigned long event, void *ptr) 39798c2ecf20Sopenharmony_ci{ 39808c2ecf20Sopenharmony_ci switch (event) { 39818c2ecf20Sopenharmony_ci case NETDEV_PRECHANGEUPPER: 39828c2ecf20Sopenharmony_ci case NETDEV_CHANGEUPPER: 39838c2ecf20Sopenharmony_ci return mlxsw_sp_netdevice_port_upper_event(lower_dev, port_dev, 39848c2ecf20Sopenharmony_ci event, ptr); 39858c2ecf20Sopenharmony_ci case NETDEV_CHANGELOWERSTATE: 39868c2ecf20Sopenharmony_ci return mlxsw_sp_netdevice_port_lower_event(port_dev, event, 39878c2ecf20Sopenharmony_ci ptr); 39888c2ecf20Sopenharmony_ci } 39898c2ecf20Sopenharmony_ci 39908c2ecf20Sopenharmony_ci return 0; 39918c2ecf20Sopenharmony_ci} 39928c2ecf20Sopenharmony_ci 39938c2ecf20Sopenharmony_cistatic int mlxsw_sp_netdevice_lag_event(struct net_device *lag_dev, 39948c2ecf20Sopenharmony_ci unsigned long event, void *ptr) 39958c2ecf20Sopenharmony_ci{ 39968c2ecf20Sopenharmony_ci struct net_device *dev; 39978c2ecf20Sopenharmony_ci struct list_head *iter; 39988c2ecf20Sopenharmony_ci int ret; 39998c2ecf20Sopenharmony_ci 40008c2ecf20Sopenharmony_ci netdev_for_each_lower_dev(lag_dev, dev, iter) { 40018c2ecf20Sopenharmony_ci if (mlxsw_sp_port_dev_check(dev)) { 40028c2ecf20Sopenharmony_ci ret = mlxsw_sp_netdevice_port_event(lag_dev, dev, event, 40038c2ecf20Sopenharmony_ci ptr); 40048c2ecf20Sopenharmony_ci if (ret) 40058c2ecf20Sopenharmony_ci return ret; 40068c2ecf20Sopenharmony_ci } 40078c2ecf20Sopenharmony_ci } 40088c2ecf20Sopenharmony_ci 40098c2ecf20Sopenharmony_ci return 0; 40108c2ecf20Sopenharmony_ci} 40118c2ecf20Sopenharmony_ci 40128c2ecf20Sopenharmony_cistatic int mlxsw_sp_netdevice_port_vlan_event(struct net_device *vlan_dev, 40138c2ecf20Sopenharmony_ci struct net_device *dev, 40148c2ecf20Sopenharmony_ci unsigned long event, void *ptr, 40158c2ecf20Sopenharmony_ci u16 vid) 40168c2ecf20Sopenharmony_ci{ 40178c2ecf20Sopenharmony_ci struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(dev); 40188c2ecf20Sopenharmony_ci struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; 40198c2ecf20Sopenharmony_ci struct netdev_notifier_changeupper_info *info = ptr; 40208c2ecf20Sopenharmony_ci struct netlink_ext_ack *extack; 40218c2ecf20Sopenharmony_ci struct net_device *upper_dev; 40228c2ecf20Sopenharmony_ci int err = 0; 40238c2ecf20Sopenharmony_ci 40248c2ecf20Sopenharmony_ci extack = netdev_notifier_info_to_extack(&info->info); 40258c2ecf20Sopenharmony_ci 40268c2ecf20Sopenharmony_ci switch (event) { 40278c2ecf20Sopenharmony_ci case NETDEV_PRECHANGEUPPER: 40288c2ecf20Sopenharmony_ci upper_dev = info->upper_dev; 40298c2ecf20Sopenharmony_ci if (!netif_is_bridge_master(upper_dev) && 40308c2ecf20Sopenharmony_ci !netif_is_macvlan(upper_dev)) { 40318c2ecf20Sopenharmony_ci NL_SET_ERR_MSG_MOD(extack, "Unknown upper device type"); 40328c2ecf20Sopenharmony_ci return -EINVAL; 40338c2ecf20Sopenharmony_ci } 40348c2ecf20Sopenharmony_ci if (!info->linking) 40358c2ecf20Sopenharmony_ci break; 40368c2ecf20Sopenharmony_ci if (netif_is_bridge_master(upper_dev) && 40378c2ecf20Sopenharmony_ci !mlxsw_sp_bridge_device_is_offloaded(mlxsw_sp, upper_dev) && 40388c2ecf20Sopenharmony_ci mlxsw_sp_bridge_has_vxlan(upper_dev) && 40398c2ecf20Sopenharmony_ci !mlxsw_sp_bridge_vxlan_is_valid(upper_dev, extack)) 40408c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 40418c2ecf20Sopenharmony_ci if (netdev_has_any_upper_dev(upper_dev) && 40428c2ecf20Sopenharmony_ci (!netif_is_bridge_master(upper_dev) || 40438c2ecf20Sopenharmony_ci !mlxsw_sp_bridge_device_is_offloaded(mlxsw_sp, 40448c2ecf20Sopenharmony_ci upper_dev))) { 40458c2ecf20Sopenharmony_ci NL_SET_ERR_MSG_MOD(extack, "Enslaving a port to a device that already has an upper device is not supported"); 40468c2ecf20Sopenharmony_ci return -EINVAL; 40478c2ecf20Sopenharmony_ci } 40488c2ecf20Sopenharmony_ci if (netif_is_macvlan(upper_dev) && 40498c2ecf20Sopenharmony_ci !mlxsw_sp_rif_exists(mlxsw_sp, vlan_dev)) { 40508c2ecf20Sopenharmony_ci NL_SET_ERR_MSG_MOD(extack, "macvlan is only supported on top of router interfaces"); 40518c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 40528c2ecf20Sopenharmony_ci } 40538c2ecf20Sopenharmony_ci break; 40548c2ecf20Sopenharmony_ci case NETDEV_CHANGEUPPER: 40558c2ecf20Sopenharmony_ci upper_dev = info->upper_dev; 40568c2ecf20Sopenharmony_ci if (netif_is_bridge_master(upper_dev)) { 40578c2ecf20Sopenharmony_ci if (info->linking) 40588c2ecf20Sopenharmony_ci err = mlxsw_sp_port_bridge_join(mlxsw_sp_port, 40598c2ecf20Sopenharmony_ci vlan_dev, 40608c2ecf20Sopenharmony_ci upper_dev, 40618c2ecf20Sopenharmony_ci extack); 40628c2ecf20Sopenharmony_ci else 40638c2ecf20Sopenharmony_ci mlxsw_sp_port_bridge_leave(mlxsw_sp_port, 40648c2ecf20Sopenharmony_ci vlan_dev, 40658c2ecf20Sopenharmony_ci upper_dev); 40668c2ecf20Sopenharmony_ci } else if (netif_is_macvlan(upper_dev)) { 40678c2ecf20Sopenharmony_ci if (!info->linking) 40688c2ecf20Sopenharmony_ci mlxsw_sp_rif_macvlan_del(mlxsw_sp, upper_dev); 40698c2ecf20Sopenharmony_ci } else { 40708c2ecf20Sopenharmony_ci err = -EINVAL; 40718c2ecf20Sopenharmony_ci WARN_ON(1); 40728c2ecf20Sopenharmony_ci } 40738c2ecf20Sopenharmony_ci break; 40748c2ecf20Sopenharmony_ci } 40758c2ecf20Sopenharmony_ci 40768c2ecf20Sopenharmony_ci return err; 40778c2ecf20Sopenharmony_ci} 40788c2ecf20Sopenharmony_ci 40798c2ecf20Sopenharmony_cistatic int mlxsw_sp_netdevice_lag_port_vlan_event(struct net_device *vlan_dev, 40808c2ecf20Sopenharmony_ci struct net_device *lag_dev, 40818c2ecf20Sopenharmony_ci unsigned long event, 40828c2ecf20Sopenharmony_ci void *ptr, u16 vid) 40838c2ecf20Sopenharmony_ci{ 40848c2ecf20Sopenharmony_ci struct net_device *dev; 40858c2ecf20Sopenharmony_ci struct list_head *iter; 40868c2ecf20Sopenharmony_ci int ret; 40878c2ecf20Sopenharmony_ci 40888c2ecf20Sopenharmony_ci netdev_for_each_lower_dev(lag_dev, dev, iter) { 40898c2ecf20Sopenharmony_ci if (mlxsw_sp_port_dev_check(dev)) { 40908c2ecf20Sopenharmony_ci ret = mlxsw_sp_netdevice_port_vlan_event(vlan_dev, dev, 40918c2ecf20Sopenharmony_ci event, ptr, 40928c2ecf20Sopenharmony_ci vid); 40938c2ecf20Sopenharmony_ci if (ret) 40948c2ecf20Sopenharmony_ci return ret; 40958c2ecf20Sopenharmony_ci } 40968c2ecf20Sopenharmony_ci } 40978c2ecf20Sopenharmony_ci 40988c2ecf20Sopenharmony_ci return 0; 40998c2ecf20Sopenharmony_ci} 41008c2ecf20Sopenharmony_ci 41018c2ecf20Sopenharmony_cistatic int mlxsw_sp_netdevice_bridge_vlan_event(struct net_device *vlan_dev, 41028c2ecf20Sopenharmony_ci struct net_device *br_dev, 41038c2ecf20Sopenharmony_ci unsigned long event, void *ptr, 41048c2ecf20Sopenharmony_ci u16 vid) 41058c2ecf20Sopenharmony_ci{ 41068c2ecf20Sopenharmony_ci struct mlxsw_sp *mlxsw_sp = mlxsw_sp_lower_get(vlan_dev); 41078c2ecf20Sopenharmony_ci struct netdev_notifier_changeupper_info *info = ptr; 41088c2ecf20Sopenharmony_ci struct netlink_ext_ack *extack; 41098c2ecf20Sopenharmony_ci struct net_device *upper_dev; 41108c2ecf20Sopenharmony_ci 41118c2ecf20Sopenharmony_ci if (!mlxsw_sp) 41128c2ecf20Sopenharmony_ci return 0; 41138c2ecf20Sopenharmony_ci 41148c2ecf20Sopenharmony_ci extack = netdev_notifier_info_to_extack(&info->info); 41158c2ecf20Sopenharmony_ci 41168c2ecf20Sopenharmony_ci switch (event) { 41178c2ecf20Sopenharmony_ci case NETDEV_PRECHANGEUPPER: 41188c2ecf20Sopenharmony_ci upper_dev = info->upper_dev; 41198c2ecf20Sopenharmony_ci if (!netif_is_macvlan(upper_dev)) { 41208c2ecf20Sopenharmony_ci NL_SET_ERR_MSG_MOD(extack, "Unknown upper device type"); 41218c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 41228c2ecf20Sopenharmony_ci } 41238c2ecf20Sopenharmony_ci if (!info->linking) 41248c2ecf20Sopenharmony_ci break; 41258c2ecf20Sopenharmony_ci if (netif_is_macvlan(upper_dev) && 41268c2ecf20Sopenharmony_ci !mlxsw_sp_rif_exists(mlxsw_sp, vlan_dev)) { 41278c2ecf20Sopenharmony_ci NL_SET_ERR_MSG_MOD(extack, "macvlan is only supported on top of router interfaces"); 41288c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 41298c2ecf20Sopenharmony_ci } 41308c2ecf20Sopenharmony_ci break; 41318c2ecf20Sopenharmony_ci case NETDEV_CHANGEUPPER: 41328c2ecf20Sopenharmony_ci upper_dev = info->upper_dev; 41338c2ecf20Sopenharmony_ci if (info->linking) 41348c2ecf20Sopenharmony_ci break; 41358c2ecf20Sopenharmony_ci if (netif_is_macvlan(upper_dev)) 41368c2ecf20Sopenharmony_ci mlxsw_sp_rif_macvlan_del(mlxsw_sp, upper_dev); 41378c2ecf20Sopenharmony_ci break; 41388c2ecf20Sopenharmony_ci } 41398c2ecf20Sopenharmony_ci 41408c2ecf20Sopenharmony_ci return 0; 41418c2ecf20Sopenharmony_ci} 41428c2ecf20Sopenharmony_ci 41438c2ecf20Sopenharmony_cistatic int mlxsw_sp_netdevice_vlan_event(struct net_device *vlan_dev, 41448c2ecf20Sopenharmony_ci unsigned long event, void *ptr) 41458c2ecf20Sopenharmony_ci{ 41468c2ecf20Sopenharmony_ci struct net_device *real_dev = vlan_dev_real_dev(vlan_dev); 41478c2ecf20Sopenharmony_ci u16 vid = vlan_dev_vlan_id(vlan_dev); 41488c2ecf20Sopenharmony_ci 41498c2ecf20Sopenharmony_ci if (mlxsw_sp_port_dev_check(real_dev)) 41508c2ecf20Sopenharmony_ci return mlxsw_sp_netdevice_port_vlan_event(vlan_dev, real_dev, 41518c2ecf20Sopenharmony_ci event, ptr, vid); 41528c2ecf20Sopenharmony_ci else if (netif_is_lag_master(real_dev)) 41538c2ecf20Sopenharmony_ci return mlxsw_sp_netdevice_lag_port_vlan_event(vlan_dev, 41548c2ecf20Sopenharmony_ci real_dev, event, 41558c2ecf20Sopenharmony_ci ptr, vid); 41568c2ecf20Sopenharmony_ci else if (netif_is_bridge_master(real_dev)) 41578c2ecf20Sopenharmony_ci return mlxsw_sp_netdevice_bridge_vlan_event(vlan_dev, real_dev, 41588c2ecf20Sopenharmony_ci event, ptr, vid); 41598c2ecf20Sopenharmony_ci 41608c2ecf20Sopenharmony_ci return 0; 41618c2ecf20Sopenharmony_ci} 41628c2ecf20Sopenharmony_ci 41638c2ecf20Sopenharmony_cistatic int mlxsw_sp_netdevice_bridge_event(struct net_device *br_dev, 41648c2ecf20Sopenharmony_ci unsigned long event, void *ptr) 41658c2ecf20Sopenharmony_ci{ 41668c2ecf20Sopenharmony_ci struct mlxsw_sp *mlxsw_sp = mlxsw_sp_lower_get(br_dev); 41678c2ecf20Sopenharmony_ci struct netdev_notifier_changeupper_info *info = ptr; 41688c2ecf20Sopenharmony_ci struct netlink_ext_ack *extack; 41698c2ecf20Sopenharmony_ci struct net_device *upper_dev; 41708c2ecf20Sopenharmony_ci 41718c2ecf20Sopenharmony_ci if (!mlxsw_sp) 41728c2ecf20Sopenharmony_ci return 0; 41738c2ecf20Sopenharmony_ci 41748c2ecf20Sopenharmony_ci extack = netdev_notifier_info_to_extack(&info->info); 41758c2ecf20Sopenharmony_ci 41768c2ecf20Sopenharmony_ci switch (event) { 41778c2ecf20Sopenharmony_ci case NETDEV_PRECHANGEUPPER: 41788c2ecf20Sopenharmony_ci upper_dev = info->upper_dev; 41798c2ecf20Sopenharmony_ci if (!is_vlan_dev(upper_dev) && !netif_is_macvlan(upper_dev)) { 41808c2ecf20Sopenharmony_ci NL_SET_ERR_MSG_MOD(extack, "Unknown upper device type"); 41818c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 41828c2ecf20Sopenharmony_ci } 41838c2ecf20Sopenharmony_ci if (!info->linking) 41848c2ecf20Sopenharmony_ci break; 41858c2ecf20Sopenharmony_ci if (netif_is_macvlan(upper_dev) && 41868c2ecf20Sopenharmony_ci !mlxsw_sp_rif_exists(mlxsw_sp, br_dev)) { 41878c2ecf20Sopenharmony_ci NL_SET_ERR_MSG_MOD(extack, "macvlan is only supported on top of router interfaces"); 41888c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 41898c2ecf20Sopenharmony_ci } 41908c2ecf20Sopenharmony_ci break; 41918c2ecf20Sopenharmony_ci case NETDEV_CHANGEUPPER: 41928c2ecf20Sopenharmony_ci upper_dev = info->upper_dev; 41938c2ecf20Sopenharmony_ci if (info->linking) 41948c2ecf20Sopenharmony_ci break; 41958c2ecf20Sopenharmony_ci if (is_vlan_dev(upper_dev)) 41968c2ecf20Sopenharmony_ci mlxsw_sp_rif_destroy_by_dev(mlxsw_sp, upper_dev); 41978c2ecf20Sopenharmony_ci if (netif_is_macvlan(upper_dev)) 41988c2ecf20Sopenharmony_ci mlxsw_sp_rif_macvlan_del(mlxsw_sp, upper_dev); 41998c2ecf20Sopenharmony_ci break; 42008c2ecf20Sopenharmony_ci } 42018c2ecf20Sopenharmony_ci 42028c2ecf20Sopenharmony_ci return 0; 42038c2ecf20Sopenharmony_ci} 42048c2ecf20Sopenharmony_ci 42058c2ecf20Sopenharmony_cistatic int mlxsw_sp_netdevice_macvlan_event(struct net_device *macvlan_dev, 42068c2ecf20Sopenharmony_ci unsigned long event, void *ptr) 42078c2ecf20Sopenharmony_ci{ 42088c2ecf20Sopenharmony_ci struct mlxsw_sp *mlxsw_sp = mlxsw_sp_lower_get(macvlan_dev); 42098c2ecf20Sopenharmony_ci struct netdev_notifier_changeupper_info *info = ptr; 42108c2ecf20Sopenharmony_ci struct netlink_ext_ack *extack; 42118c2ecf20Sopenharmony_ci 42128c2ecf20Sopenharmony_ci if (!mlxsw_sp || event != NETDEV_PRECHANGEUPPER) 42138c2ecf20Sopenharmony_ci return 0; 42148c2ecf20Sopenharmony_ci 42158c2ecf20Sopenharmony_ci extack = netdev_notifier_info_to_extack(&info->info); 42168c2ecf20Sopenharmony_ci 42178c2ecf20Sopenharmony_ci /* VRF enslavement is handled in mlxsw_sp_netdevice_vrf_event() */ 42188c2ecf20Sopenharmony_ci NL_SET_ERR_MSG_MOD(extack, "Unknown upper device type"); 42198c2ecf20Sopenharmony_ci 42208c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 42218c2ecf20Sopenharmony_ci} 42228c2ecf20Sopenharmony_ci 42238c2ecf20Sopenharmony_cistatic bool mlxsw_sp_is_vrf_event(unsigned long event, void *ptr) 42248c2ecf20Sopenharmony_ci{ 42258c2ecf20Sopenharmony_ci struct netdev_notifier_changeupper_info *info = ptr; 42268c2ecf20Sopenharmony_ci 42278c2ecf20Sopenharmony_ci if (event != NETDEV_PRECHANGEUPPER && event != NETDEV_CHANGEUPPER) 42288c2ecf20Sopenharmony_ci return false; 42298c2ecf20Sopenharmony_ci return netif_is_l3_master(info->upper_dev); 42308c2ecf20Sopenharmony_ci} 42318c2ecf20Sopenharmony_ci 42328c2ecf20Sopenharmony_cistatic int mlxsw_sp_netdevice_vxlan_event(struct mlxsw_sp *mlxsw_sp, 42338c2ecf20Sopenharmony_ci struct net_device *dev, 42348c2ecf20Sopenharmony_ci unsigned long event, void *ptr) 42358c2ecf20Sopenharmony_ci{ 42368c2ecf20Sopenharmony_ci struct netdev_notifier_changeupper_info *cu_info; 42378c2ecf20Sopenharmony_ci struct netdev_notifier_info *info = ptr; 42388c2ecf20Sopenharmony_ci struct netlink_ext_ack *extack; 42398c2ecf20Sopenharmony_ci struct net_device *upper_dev; 42408c2ecf20Sopenharmony_ci 42418c2ecf20Sopenharmony_ci extack = netdev_notifier_info_to_extack(info); 42428c2ecf20Sopenharmony_ci 42438c2ecf20Sopenharmony_ci switch (event) { 42448c2ecf20Sopenharmony_ci case NETDEV_CHANGEUPPER: 42458c2ecf20Sopenharmony_ci cu_info = container_of(info, 42468c2ecf20Sopenharmony_ci struct netdev_notifier_changeupper_info, 42478c2ecf20Sopenharmony_ci info); 42488c2ecf20Sopenharmony_ci upper_dev = cu_info->upper_dev; 42498c2ecf20Sopenharmony_ci if (!netif_is_bridge_master(upper_dev)) 42508c2ecf20Sopenharmony_ci return 0; 42518c2ecf20Sopenharmony_ci if (!mlxsw_sp_lower_get(upper_dev)) 42528c2ecf20Sopenharmony_ci return 0; 42538c2ecf20Sopenharmony_ci if (!mlxsw_sp_bridge_vxlan_is_valid(upper_dev, extack)) 42548c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 42558c2ecf20Sopenharmony_ci if (cu_info->linking) { 42568c2ecf20Sopenharmony_ci if (!netif_running(dev)) 42578c2ecf20Sopenharmony_ci return 0; 42588c2ecf20Sopenharmony_ci /* When the bridge is VLAN-aware, the VNI of the VxLAN 42598c2ecf20Sopenharmony_ci * device needs to be mapped to a VLAN, but at this 42608c2ecf20Sopenharmony_ci * point no VLANs are configured on the VxLAN device 42618c2ecf20Sopenharmony_ci */ 42628c2ecf20Sopenharmony_ci if (br_vlan_enabled(upper_dev)) 42638c2ecf20Sopenharmony_ci return 0; 42648c2ecf20Sopenharmony_ci return mlxsw_sp_bridge_vxlan_join(mlxsw_sp, upper_dev, 42658c2ecf20Sopenharmony_ci dev, 0, extack); 42668c2ecf20Sopenharmony_ci } else { 42678c2ecf20Sopenharmony_ci /* VLANs were already flushed, which triggered the 42688c2ecf20Sopenharmony_ci * necessary cleanup 42698c2ecf20Sopenharmony_ci */ 42708c2ecf20Sopenharmony_ci if (br_vlan_enabled(upper_dev)) 42718c2ecf20Sopenharmony_ci return 0; 42728c2ecf20Sopenharmony_ci mlxsw_sp_bridge_vxlan_leave(mlxsw_sp, dev); 42738c2ecf20Sopenharmony_ci } 42748c2ecf20Sopenharmony_ci break; 42758c2ecf20Sopenharmony_ci case NETDEV_PRE_UP: 42768c2ecf20Sopenharmony_ci upper_dev = netdev_master_upper_dev_get(dev); 42778c2ecf20Sopenharmony_ci if (!upper_dev) 42788c2ecf20Sopenharmony_ci return 0; 42798c2ecf20Sopenharmony_ci if (!netif_is_bridge_master(upper_dev)) 42808c2ecf20Sopenharmony_ci return 0; 42818c2ecf20Sopenharmony_ci if (!mlxsw_sp_lower_get(upper_dev)) 42828c2ecf20Sopenharmony_ci return 0; 42838c2ecf20Sopenharmony_ci return mlxsw_sp_bridge_vxlan_join(mlxsw_sp, upper_dev, dev, 0, 42848c2ecf20Sopenharmony_ci extack); 42858c2ecf20Sopenharmony_ci case NETDEV_DOWN: 42868c2ecf20Sopenharmony_ci upper_dev = netdev_master_upper_dev_get(dev); 42878c2ecf20Sopenharmony_ci if (!upper_dev) 42888c2ecf20Sopenharmony_ci return 0; 42898c2ecf20Sopenharmony_ci if (!netif_is_bridge_master(upper_dev)) 42908c2ecf20Sopenharmony_ci return 0; 42918c2ecf20Sopenharmony_ci if (!mlxsw_sp_lower_get(upper_dev)) 42928c2ecf20Sopenharmony_ci return 0; 42938c2ecf20Sopenharmony_ci mlxsw_sp_bridge_vxlan_leave(mlxsw_sp, dev); 42948c2ecf20Sopenharmony_ci break; 42958c2ecf20Sopenharmony_ci } 42968c2ecf20Sopenharmony_ci 42978c2ecf20Sopenharmony_ci return 0; 42988c2ecf20Sopenharmony_ci} 42998c2ecf20Sopenharmony_ci 43008c2ecf20Sopenharmony_cistatic int mlxsw_sp_netdevice_event(struct notifier_block *nb, 43018c2ecf20Sopenharmony_ci unsigned long event, void *ptr) 43028c2ecf20Sopenharmony_ci{ 43038c2ecf20Sopenharmony_ci struct net_device *dev = netdev_notifier_info_to_dev(ptr); 43048c2ecf20Sopenharmony_ci struct mlxsw_sp_span_entry *span_entry; 43058c2ecf20Sopenharmony_ci struct mlxsw_sp *mlxsw_sp; 43068c2ecf20Sopenharmony_ci int err = 0; 43078c2ecf20Sopenharmony_ci 43088c2ecf20Sopenharmony_ci mlxsw_sp = container_of(nb, struct mlxsw_sp, netdevice_nb); 43098c2ecf20Sopenharmony_ci if (event == NETDEV_UNREGISTER) { 43108c2ecf20Sopenharmony_ci span_entry = mlxsw_sp_span_entry_find_by_port(mlxsw_sp, dev); 43118c2ecf20Sopenharmony_ci if (span_entry) 43128c2ecf20Sopenharmony_ci mlxsw_sp_span_entry_invalidate(mlxsw_sp, span_entry); 43138c2ecf20Sopenharmony_ci } 43148c2ecf20Sopenharmony_ci mlxsw_sp_span_respin(mlxsw_sp); 43158c2ecf20Sopenharmony_ci 43168c2ecf20Sopenharmony_ci if (netif_is_vxlan(dev)) 43178c2ecf20Sopenharmony_ci err = mlxsw_sp_netdevice_vxlan_event(mlxsw_sp, dev, event, ptr); 43188c2ecf20Sopenharmony_ci if (mlxsw_sp_netdev_is_ipip_ol(mlxsw_sp, dev)) 43198c2ecf20Sopenharmony_ci err = mlxsw_sp_netdevice_ipip_ol_event(mlxsw_sp, dev, 43208c2ecf20Sopenharmony_ci event, ptr); 43218c2ecf20Sopenharmony_ci else if (mlxsw_sp_netdev_is_ipip_ul(mlxsw_sp, dev)) 43228c2ecf20Sopenharmony_ci err = mlxsw_sp_netdevice_ipip_ul_event(mlxsw_sp, dev, 43238c2ecf20Sopenharmony_ci event, ptr); 43248c2ecf20Sopenharmony_ci else if (event == NETDEV_PRE_CHANGEADDR || 43258c2ecf20Sopenharmony_ci event == NETDEV_CHANGEADDR || 43268c2ecf20Sopenharmony_ci event == NETDEV_CHANGEMTU) 43278c2ecf20Sopenharmony_ci err = mlxsw_sp_netdevice_router_port_event(dev, event, ptr); 43288c2ecf20Sopenharmony_ci else if (mlxsw_sp_is_vrf_event(event, ptr)) 43298c2ecf20Sopenharmony_ci err = mlxsw_sp_netdevice_vrf_event(dev, event, ptr); 43308c2ecf20Sopenharmony_ci else if (mlxsw_sp_port_dev_check(dev)) 43318c2ecf20Sopenharmony_ci err = mlxsw_sp_netdevice_port_event(dev, dev, event, ptr); 43328c2ecf20Sopenharmony_ci else if (netif_is_lag_master(dev)) 43338c2ecf20Sopenharmony_ci err = mlxsw_sp_netdevice_lag_event(dev, event, ptr); 43348c2ecf20Sopenharmony_ci else if (is_vlan_dev(dev)) 43358c2ecf20Sopenharmony_ci err = mlxsw_sp_netdevice_vlan_event(dev, event, ptr); 43368c2ecf20Sopenharmony_ci else if (netif_is_bridge_master(dev)) 43378c2ecf20Sopenharmony_ci err = mlxsw_sp_netdevice_bridge_event(dev, event, ptr); 43388c2ecf20Sopenharmony_ci else if (netif_is_macvlan(dev)) 43398c2ecf20Sopenharmony_ci err = mlxsw_sp_netdevice_macvlan_event(dev, event, ptr); 43408c2ecf20Sopenharmony_ci 43418c2ecf20Sopenharmony_ci return notifier_from_errno(err); 43428c2ecf20Sopenharmony_ci} 43438c2ecf20Sopenharmony_ci 43448c2ecf20Sopenharmony_cistatic struct notifier_block mlxsw_sp_inetaddr_valid_nb __read_mostly = { 43458c2ecf20Sopenharmony_ci .notifier_call = mlxsw_sp_inetaddr_valid_event, 43468c2ecf20Sopenharmony_ci}; 43478c2ecf20Sopenharmony_ci 43488c2ecf20Sopenharmony_cistatic struct notifier_block mlxsw_sp_inet6addr_valid_nb __read_mostly = { 43498c2ecf20Sopenharmony_ci .notifier_call = mlxsw_sp_inet6addr_valid_event, 43508c2ecf20Sopenharmony_ci}; 43518c2ecf20Sopenharmony_ci 43528c2ecf20Sopenharmony_cistatic const struct pci_device_id mlxsw_sp1_pci_id_table[] = { 43538c2ecf20Sopenharmony_ci {PCI_VDEVICE(MELLANOX, PCI_DEVICE_ID_MELLANOX_SPECTRUM), 0}, 43548c2ecf20Sopenharmony_ci {0, }, 43558c2ecf20Sopenharmony_ci}; 43568c2ecf20Sopenharmony_ci 43578c2ecf20Sopenharmony_cistatic struct pci_driver mlxsw_sp1_pci_driver = { 43588c2ecf20Sopenharmony_ci .name = mlxsw_sp1_driver_name, 43598c2ecf20Sopenharmony_ci .id_table = mlxsw_sp1_pci_id_table, 43608c2ecf20Sopenharmony_ci}; 43618c2ecf20Sopenharmony_ci 43628c2ecf20Sopenharmony_cistatic const struct pci_device_id mlxsw_sp2_pci_id_table[] = { 43638c2ecf20Sopenharmony_ci {PCI_VDEVICE(MELLANOX, PCI_DEVICE_ID_MELLANOX_SPECTRUM2), 0}, 43648c2ecf20Sopenharmony_ci {0, }, 43658c2ecf20Sopenharmony_ci}; 43668c2ecf20Sopenharmony_ci 43678c2ecf20Sopenharmony_cistatic struct pci_driver mlxsw_sp2_pci_driver = { 43688c2ecf20Sopenharmony_ci .name = mlxsw_sp2_driver_name, 43698c2ecf20Sopenharmony_ci .id_table = mlxsw_sp2_pci_id_table, 43708c2ecf20Sopenharmony_ci}; 43718c2ecf20Sopenharmony_ci 43728c2ecf20Sopenharmony_cistatic const struct pci_device_id mlxsw_sp3_pci_id_table[] = { 43738c2ecf20Sopenharmony_ci {PCI_VDEVICE(MELLANOX, PCI_DEVICE_ID_MELLANOX_SPECTRUM3), 0}, 43748c2ecf20Sopenharmony_ci {0, }, 43758c2ecf20Sopenharmony_ci}; 43768c2ecf20Sopenharmony_ci 43778c2ecf20Sopenharmony_cistatic struct pci_driver mlxsw_sp3_pci_driver = { 43788c2ecf20Sopenharmony_ci .name = mlxsw_sp3_driver_name, 43798c2ecf20Sopenharmony_ci .id_table = mlxsw_sp3_pci_id_table, 43808c2ecf20Sopenharmony_ci}; 43818c2ecf20Sopenharmony_ci 43828c2ecf20Sopenharmony_cistatic int __init mlxsw_sp_module_init(void) 43838c2ecf20Sopenharmony_ci{ 43848c2ecf20Sopenharmony_ci int err; 43858c2ecf20Sopenharmony_ci 43868c2ecf20Sopenharmony_ci register_inetaddr_validator_notifier(&mlxsw_sp_inetaddr_valid_nb); 43878c2ecf20Sopenharmony_ci register_inet6addr_validator_notifier(&mlxsw_sp_inet6addr_valid_nb); 43888c2ecf20Sopenharmony_ci 43898c2ecf20Sopenharmony_ci err = mlxsw_core_driver_register(&mlxsw_sp1_driver); 43908c2ecf20Sopenharmony_ci if (err) 43918c2ecf20Sopenharmony_ci goto err_sp1_core_driver_register; 43928c2ecf20Sopenharmony_ci 43938c2ecf20Sopenharmony_ci err = mlxsw_core_driver_register(&mlxsw_sp2_driver); 43948c2ecf20Sopenharmony_ci if (err) 43958c2ecf20Sopenharmony_ci goto err_sp2_core_driver_register; 43968c2ecf20Sopenharmony_ci 43978c2ecf20Sopenharmony_ci err = mlxsw_core_driver_register(&mlxsw_sp3_driver); 43988c2ecf20Sopenharmony_ci if (err) 43998c2ecf20Sopenharmony_ci goto err_sp3_core_driver_register; 44008c2ecf20Sopenharmony_ci 44018c2ecf20Sopenharmony_ci err = mlxsw_pci_driver_register(&mlxsw_sp1_pci_driver); 44028c2ecf20Sopenharmony_ci if (err) 44038c2ecf20Sopenharmony_ci goto err_sp1_pci_driver_register; 44048c2ecf20Sopenharmony_ci 44058c2ecf20Sopenharmony_ci err = mlxsw_pci_driver_register(&mlxsw_sp2_pci_driver); 44068c2ecf20Sopenharmony_ci if (err) 44078c2ecf20Sopenharmony_ci goto err_sp2_pci_driver_register; 44088c2ecf20Sopenharmony_ci 44098c2ecf20Sopenharmony_ci err = mlxsw_pci_driver_register(&mlxsw_sp3_pci_driver); 44108c2ecf20Sopenharmony_ci if (err) 44118c2ecf20Sopenharmony_ci goto err_sp3_pci_driver_register; 44128c2ecf20Sopenharmony_ci 44138c2ecf20Sopenharmony_ci return 0; 44148c2ecf20Sopenharmony_ci 44158c2ecf20Sopenharmony_cierr_sp3_pci_driver_register: 44168c2ecf20Sopenharmony_ci mlxsw_pci_driver_unregister(&mlxsw_sp2_pci_driver); 44178c2ecf20Sopenharmony_cierr_sp2_pci_driver_register: 44188c2ecf20Sopenharmony_ci mlxsw_pci_driver_unregister(&mlxsw_sp1_pci_driver); 44198c2ecf20Sopenharmony_cierr_sp1_pci_driver_register: 44208c2ecf20Sopenharmony_ci mlxsw_core_driver_unregister(&mlxsw_sp3_driver); 44218c2ecf20Sopenharmony_cierr_sp3_core_driver_register: 44228c2ecf20Sopenharmony_ci mlxsw_core_driver_unregister(&mlxsw_sp2_driver); 44238c2ecf20Sopenharmony_cierr_sp2_core_driver_register: 44248c2ecf20Sopenharmony_ci mlxsw_core_driver_unregister(&mlxsw_sp1_driver); 44258c2ecf20Sopenharmony_cierr_sp1_core_driver_register: 44268c2ecf20Sopenharmony_ci unregister_inet6addr_validator_notifier(&mlxsw_sp_inet6addr_valid_nb); 44278c2ecf20Sopenharmony_ci unregister_inetaddr_validator_notifier(&mlxsw_sp_inetaddr_valid_nb); 44288c2ecf20Sopenharmony_ci return err; 44298c2ecf20Sopenharmony_ci} 44308c2ecf20Sopenharmony_ci 44318c2ecf20Sopenharmony_cistatic void __exit mlxsw_sp_module_exit(void) 44328c2ecf20Sopenharmony_ci{ 44338c2ecf20Sopenharmony_ci mlxsw_pci_driver_unregister(&mlxsw_sp3_pci_driver); 44348c2ecf20Sopenharmony_ci mlxsw_pci_driver_unregister(&mlxsw_sp2_pci_driver); 44358c2ecf20Sopenharmony_ci mlxsw_pci_driver_unregister(&mlxsw_sp1_pci_driver); 44368c2ecf20Sopenharmony_ci mlxsw_core_driver_unregister(&mlxsw_sp3_driver); 44378c2ecf20Sopenharmony_ci mlxsw_core_driver_unregister(&mlxsw_sp2_driver); 44388c2ecf20Sopenharmony_ci mlxsw_core_driver_unregister(&mlxsw_sp1_driver); 44398c2ecf20Sopenharmony_ci unregister_inet6addr_validator_notifier(&mlxsw_sp_inet6addr_valid_nb); 44408c2ecf20Sopenharmony_ci unregister_inetaddr_validator_notifier(&mlxsw_sp_inetaddr_valid_nb); 44418c2ecf20Sopenharmony_ci} 44428c2ecf20Sopenharmony_ci 44438c2ecf20Sopenharmony_cimodule_init(mlxsw_sp_module_init); 44448c2ecf20Sopenharmony_cimodule_exit(mlxsw_sp_module_exit); 44458c2ecf20Sopenharmony_ci 44468c2ecf20Sopenharmony_ciMODULE_LICENSE("Dual BSD/GPL"); 44478c2ecf20Sopenharmony_ciMODULE_AUTHOR("Jiri Pirko <jiri@mellanox.com>"); 44488c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Mellanox Spectrum driver"); 44498c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(pci, mlxsw_sp1_pci_id_table); 44508c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(pci, mlxsw_sp2_pci_id_table); 44518c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(pci, mlxsw_sp3_pci_id_table); 44528c2ecf20Sopenharmony_ciMODULE_FIRMWARE(MLXSW_SP1_FW_FILENAME); 44538c2ecf20Sopenharmony_ciMODULE_FIRMWARE(MLXSW_SP2_FW_FILENAME); 44548c2ecf20Sopenharmony_ciMODULE_FIRMWARE(MLXSW_SP3_FW_FILENAME); 4455