18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0 28c2ecf20Sopenharmony_ci/* Copyright (c) 2016-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/slab.h> 118c2ecf20Sopenharmony_ci#include <linux/device.h> 128c2ecf20Sopenharmony_ci#include <linux/skbuff.h> 138c2ecf20Sopenharmony_ci#include <linux/if_vlan.h> 148c2ecf20Sopenharmony_ci#include <net/switchdev.h> 158c2ecf20Sopenharmony_ci 168c2ecf20Sopenharmony_ci#include "pci.h" 178c2ecf20Sopenharmony_ci#include "core.h" 188c2ecf20Sopenharmony_ci#include "reg.h" 198c2ecf20Sopenharmony_ci#include "port.h" 208c2ecf20Sopenharmony_ci#include "trap.h" 218c2ecf20Sopenharmony_ci#include "txheader.h" 228c2ecf20Sopenharmony_ci#include "ib.h" 238c2ecf20Sopenharmony_ci 248c2ecf20Sopenharmony_cistatic const char mlxsw_sib_driver_name[] = "mlxsw_switchib"; 258c2ecf20Sopenharmony_cistatic const char mlxsw_sib2_driver_name[] = "mlxsw_switchib2"; 268c2ecf20Sopenharmony_ci 278c2ecf20Sopenharmony_cistruct mlxsw_sib_port; 288c2ecf20Sopenharmony_ci 298c2ecf20Sopenharmony_cistruct mlxsw_sib { 308c2ecf20Sopenharmony_ci struct mlxsw_sib_port **ports; 318c2ecf20Sopenharmony_ci struct mlxsw_core *core; 328c2ecf20Sopenharmony_ci const struct mlxsw_bus_info *bus_info; 338c2ecf20Sopenharmony_ci u8 hw_id[ETH_ALEN]; 348c2ecf20Sopenharmony_ci}; 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_cistruct mlxsw_sib_port { 378c2ecf20Sopenharmony_ci struct mlxsw_sib *mlxsw_sib; 388c2ecf20Sopenharmony_ci u8 local_port; 398c2ecf20Sopenharmony_ci struct { 408c2ecf20Sopenharmony_ci u8 module; 418c2ecf20Sopenharmony_ci } mapping; 428c2ecf20Sopenharmony_ci}; 438c2ecf20Sopenharmony_ci 448c2ecf20Sopenharmony_ci/* tx_v1_hdr_version 458c2ecf20Sopenharmony_ci * Tx header version. 468c2ecf20Sopenharmony_ci * Must be set to 1. 478c2ecf20Sopenharmony_ci */ 488c2ecf20Sopenharmony_ciMLXSW_ITEM32(tx_v1, hdr, version, 0x00, 28, 4); 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_ci/* tx_v1_hdr_ctl 518c2ecf20Sopenharmony_ci * Packet control type. 528c2ecf20Sopenharmony_ci * 0 - Ethernet control (e.g. EMADs, LACP) 538c2ecf20Sopenharmony_ci * 1 - Ethernet data 548c2ecf20Sopenharmony_ci */ 558c2ecf20Sopenharmony_ciMLXSW_ITEM32(tx_v1, hdr, ctl, 0x00, 26, 2); 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_ci/* tx_v1_hdr_proto 588c2ecf20Sopenharmony_ci * Packet protocol type. Must be set to 1 (Ethernet). 598c2ecf20Sopenharmony_ci */ 608c2ecf20Sopenharmony_ciMLXSW_ITEM32(tx_v1, hdr, proto, 0x00, 21, 3); 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_ci/* tx_v1_hdr_swid 638c2ecf20Sopenharmony_ci * Switch partition ID. Must be set to 0. 648c2ecf20Sopenharmony_ci */ 658c2ecf20Sopenharmony_ciMLXSW_ITEM32(tx_v1, hdr, swid, 0x00, 12, 3); 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_ci/* tx_v1_hdr_control_tclass 688c2ecf20Sopenharmony_ci * Indicates if the packet should use the control TClass and not one 698c2ecf20Sopenharmony_ci * of the data TClasses. 708c2ecf20Sopenharmony_ci */ 718c2ecf20Sopenharmony_ciMLXSW_ITEM32(tx_v1, hdr, control_tclass, 0x00, 6, 1); 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_ci/* tx_v1_hdr_port_mid 748c2ecf20Sopenharmony_ci * Destination local port for unicast packets. 758c2ecf20Sopenharmony_ci * Destination multicast ID for multicast packets. 768c2ecf20Sopenharmony_ci * 778c2ecf20Sopenharmony_ci * Control packets are directed to a specific egress port, while data 788c2ecf20Sopenharmony_ci * packets are transmitted through the CPU port (0) into the switch partition, 798c2ecf20Sopenharmony_ci * where forwarding rules are applied. 808c2ecf20Sopenharmony_ci */ 818c2ecf20Sopenharmony_ciMLXSW_ITEM32(tx_v1, hdr, port_mid, 0x04, 16, 16); 828c2ecf20Sopenharmony_ci 838c2ecf20Sopenharmony_ci/* tx_v1_hdr_type 848c2ecf20Sopenharmony_ci * 0 - Data packets 858c2ecf20Sopenharmony_ci * 6 - Control packets 868c2ecf20Sopenharmony_ci */ 878c2ecf20Sopenharmony_ciMLXSW_ITEM32(tx_v1, hdr, type, 0x0C, 0, 4); 888c2ecf20Sopenharmony_ci 898c2ecf20Sopenharmony_cistatic void 908c2ecf20Sopenharmony_cimlxsw_sib_tx_v1_hdr_construct(struct sk_buff *skb, 918c2ecf20Sopenharmony_ci const struct mlxsw_tx_info *tx_info) 928c2ecf20Sopenharmony_ci{ 938c2ecf20Sopenharmony_ci char *txhdr = skb_push(skb, MLXSW_TXHDR_LEN); 948c2ecf20Sopenharmony_ci 958c2ecf20Sopenharmony_ci memset(txhdr, 0, MLXSW_TXHDR_LEN); 968c2ecf20Sopenharmony_ci 978c2ecf20Sopenharmony_ci mlxsw_tx_v1_hdr_version_set(txhdr, MLXSW_TXHDR_VERSION_1); 988c2ecf20Sopenharmony_ci mlxsw_tx_v1_hdr_ctl_set(txhdr, MLXSW_TXHDR_ETH_CTL); 998c2ecf20Sopenharmony_ci mlxsw_tx_v1_hdr_proto_set(txhdr, MLXSW_TXHDR_PROTO_ETH); 1008c2ecf20Sopenharmony_ci mlxsw_tx_v1_hdr_swid_set(txhdr, 0); 1018c2ecf20Sopenharmony_ci mlxsw_tx_v1_hdr_control_tclass_set(txhdr, 1); 1028c2ecf20Sopenharmony_ci mlxsw_tx_v1_hdr_port_mid_set(txhdr, tx_info->local_port); 1038c2ecf20Sopenharmony_ci mlxsw_tx_v1_hdr_type_set(txhdr, MLXSW_TXHDR_TYPE_CONTROL); 1048c2ecf20Sopenharmony_ci} 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_cistatic int mlxsw_sib_hw_id_get(struct mlxsw_sib *mlxsw_sib) 1078c2ecf20Sopenharmony_ci{ 1088c2ecf20Sopenharmony_ci char spad_pl[MLXSW_REG_SPAD_LEN] = {0}; 1098c2ecf20Sopenharmony_ci int err; 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_ci err = mlxsw_reg_query(mlxsw_sib->core, MLXSW_REG(spad), spad_pl); 1128c2ecf20Sopenharmony_ci if (err) 1138c2ecf20Sopenharmony_ci return err; 1148c2ecf20Sopenharmony_ci mlxsw_reg_spad_base_mac_memcpy_from(spad_pl, mlxsw_sib->hw_id); 1158c2ecf20Sopenharmony_ci return 0; 1168c2ecf20Sopenharmony_ci} 1178c2ecf20Sopenharmony_ci 1188c2ecf20Sopenharmony_cistatic int 1198c2ecf20Sopenharmony_cimlxsw_sib_port_admin_status_set(struct mlxsw_sib_port *mlxsw_sib_port, 1208c2ecf20Sopenharmony_ci bool is_up) 1218c2ecf20Sopenharmony_ci{ 1228c2ecf20Sopenharmony_ci struct mlxsw_sib *mlxsw_sib = mlxsw_sib_port->mlxsw_sib; 1238c2ecf20Sopenharmony_ci char paos_pl[MLXSW_REG_PAOS_LEN]; 1248c2ecf20Sopenharmony_ci 1258c2ecf20Sopenharmony_ci mlxsw_reg_paos_pack(paos_pl, mlxsw_sib_port->local_port, 1268c2ecf20Sopenharmony_ci is_up ? MLXSW_PORT_ADMIN_STATUS_UP : 1278c2ecf20Sopenharmony_ci MLXSW_PORT_ADMIN_STATUS_DOWN); 1288c2ecf20Sopenharmony_ci return mlxsw_reg_write(mlxsw_sib->core, MLXSW_REG(paos), paos_pl); 1298c2ecf20Sopenharmony_ci} 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_cistatic int mlxsw_sib_port_mtu_set(struct mlxsw_sib_port *mlxsw_sib_port, 1328c2ecf20Sopenharmony_ci u16 mtu) 1338c2ecf20Sopenharmony_ci{ 1348c2ecf20Sopenharmony_ci struct mlxsw_sib *mlxsw_sib = mlxsw_sib_port->mlxsw_sib; 1358c2ecf20Sopenharmony_ci char pmtu_pl[MLXSW_REG_PMTU_LEN]; 1368c2ecf20Sopenharmony_ci int max_mtu; 1378c2ecf20Sopenharmony_ci int err; 1388c2ecf20Sopenharmony_ci 1398c2ecf20Sopenharmony_ci mlxsw_reg_pmtu_pack(pmtu_pl, mlxsw_sib_port->local_port, 0); 1408c2ecf20Sopenharmony_ci err = mlxsw_reg_query(mlxsw_sib->core, MLXSW_REG(pmtu), pmtu_pl); 1418c2ecf20Sopenharmony_ci if (err) 1428c2ecf20Sopenharmony_ci return err; 1438c2ecf20Sopenharmony_ci max_mtu = mlxsw_reg_pmtu_max_mtu_get(pmtu_pl); 1448c2ecf20Sopenharmony_ci 1458c2ecf20Sopenharmony_ci if (mtu > max_mtu) 1468c2ecf20Sopenharmony_ci return -EINVAL; 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_ci mlxsw_reg_pmtu_pack(pmtu_pl, mlxsw_sib_port->local_port, mtu); 1498c2ecf20Sopenharmony_ci return mlxsw_reg_write(mlxsw_sib->core, MLXSW_REG(pmtu), pmtu_pl); 1508c2ecf20Sopenharmony_ci} 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_cistatic int mlxsw_sib_port_set(struct mlxsw_sib_port *mlxsw_sib_port, u8 port) 1538c2ecf20Sopenharmony_ci{ 1548c2ecf20Sopenharmony_ci struct mlxsw_sib *mlxsw_sib = mlxsw_sib_port->mlxsw_sib; 1558c2ecf20Sopenharmony_ci char plib_pl[MLXSW_REG_PLIB_LEN] = {0}; 1568c2ecf20Sopenharmony_ci int err; 1578c2ecf20Sopenharmony_ci 1588c2ecf20Sopenharmony_ci mlxsw_reg_plib_local_port_set(plib_pl, mlxsw_sib_port->local_port); 1598c2ecf20Sopenharmony_ci mlxsw_reg_plib_ib_port_set(plib_pl, port); 1608c2ecf20Sopenharmony_ci err = mlxsw_reg_write(mlxsw_sib->core, MLXSW_REG(plib), plib_pl); 1618c2ecf20Sopenharmony_ci return err; 1628c2ecf20Sopenharmony_ci} 1638c2ecf20Sopenharmony_ci 1648c2ecf20Sopenharmony_cistatic int mlxsw_sib_port_swid_set(struct mlxsw_sib_port *mlxsw_sib_port, 1658c2ecf20Sopenharmony_ci u8 swid) 1668c2ecf20Sopenharmony_ci{ 1678c2ecf20Sopenharmony_ci struct mlxsw_sib *mlxsw_sib = mlxsw_sib_port->mlxsw_sib; 1688c2ecf20Sopenharmony_ci char pspa_pl[MLXSW_REG_PSPA_LEN]; 1698c2ecf20Sopenharmony_ci 1708c2ecf20Sopenharmony_ci mlxsw_reg_pspa_pack(pspa_pl, swid, mlxsw_sib_port->local_port); 1718c2ecf20Sopenharmony_ci return mlxsw_reg_write(mlxsw_sib->core, MLXSW_REG(pspa), pspa_pl); 1728c2ecf20Sopenharmony_ci} 1738c2ecf20Sopenharmony_ci 1748c2ecf20Sopenharmony_cistatic int mlxsw_sib_port_module_info_get(struct mlxsw_sib *mlxsw_sib, 1758c2ecf20Sopenharmony_ci u8 local_port, u8 *p_module, 1768c2ecf20Sopenharmony_ci u8 *p_width) 1778c2ecf20Sopenharmony_ci{ 1788c2ecf20Sopenharmony_ci char pmlp_pl[MLXSW_REG_PMLP_LEN]; 1798c2ecf20Sopenharmony_ci int err; 1808c2ecf20Sopenharmony_ci 1818c2ecf20Sopenharmony_ci mlxsw_reg_pmlp_pack(pmlp_pl, local_port); 1828c2ecf20Sopenharmony_ci err = mlxsw_reg_query(mlxsw_sib->core, MLXSW_REG(pmlp), pmlp_pl); 1838c2ecf20Sopenharmony_ci if (err) 1848c2ecf20Sopenharmony_ci return err; 1858c2ecf20Sopenharmony_ci *p_module = mlxsw_reg_pmlp_module_get(pmlp_pl, 0); 1868c2ecf20Sopenharmony_ci *p_width = mlxsw_reg_pmlp_width_get(pmlp_pl); 1878c2ecf20Sopenharmony_ci return 0; 1888c2ecf20Sopenharmony_ci} 1898c2ecf20Sopenharmony_ci 1908c2ecf20Sopenharmony_cistatic int mlxsw_sib_port_speed_set(struct mlxsw_sib_port *mlxsw_sib_port, 1918c2ecf20Sopenharmony_ci u16 speed, u16 width) 1928c2ecf20Sopenharmony_ci{ 1938c2ecf20Sopenharmony_ci struct mlxsw_sib *mlxsw_sib = mlxsw_sib_port->mlxsw_sib; 1948c2ecf20Sopenharmony_ci char ptys_pl[MLXSW_REG_PTYS_LEN]; 1958c2ecf20Sopenharmony_ci 1968c2ecf20Sopenharmony_ci mlxsw_reg_ptys_ib_pack(ptys_pl, mlxsw_sib_port->local_port, speed, 1978c2ecf20Sopenharmony_ci width); 1988c2ecf20Sopenharmony_ci return mlxsw_reg_write(mlxsw_sib->core, MLXSW_REG(ptys), ptys_pl); 1998c2ecf20Sopenharmony_ci} 2008c2ecf20Sopenharmony_ci 2018c2ecf20Sopenharmony_cistatic bool mlxsw_sib_port_created(struct mlxsw_sib *mlxsw_sib, u8 local_port) 2028c2ecf20Sopenharmony_ci{ 2038c2ecf20Sopenharmony_ci return mlxsw_sib->ports[local_port] != NULL; 2048c2ecf20Sopenharmony_ci} 2058c2ecf20Sopenharmony_ci 2068c2ecf20Sopenharmony_cistatic int __mlxsw_sib_port_create(struct mlxsw_sib *mlxsw_sib, u8 local_port, 2078c2ecf20Sopenharmony_ci u8 module, u8 width) 2088c2ecf20Sopenharmony_ci{ 2098c2ecf20Sopenharmony_ci struct mlxsw_sib_port *mlxsw_sib_port; 2108c2ecf20Sopenharmony_ci int err; 2118c2ecf20Sopenharmony_ci 2128c2ecf20Sopenharmony_ci mlxsw_sib_port = kzalloc(sizeof(*mlxsw_sib_port), GFP_KERNEL); 2138c2ecf20Sopenharmony_ci if (!mlxsw_sib_port) 2148c2ecf20Sopenharmony_ci return -ENOMEM; 2158c2ecf20Sopenharmony_ci mlxsw_sib_port->mlxsw_sib = mlxsw_sib; 2168c2ecf20Sopenharmony_ci mlxsw_sib_port->local_port = local_port; 2178c2ecf20Sopenharmony_ci mlxsw_sib_port->mapping.module = module; 2188c2ecf20Sopenharmony_ci 2198c2ecf20Sopenharmony_ci err = mlxsw_sib_port_swid_set(mlxsw_sib_port, 0); 2208c2ecf20Sopenharmony_ci if (err) { 2218c2ecf20Sopenharmony_ci dev_err(mlxsw_sib->bus_info->dev, "Port %d: Failed to set SWID\n", 2228c2ecf20Sopenharmony_ci mlxsw_sib_port->local_port); 2238c2ecf20Sopenharmony_ci goto err_port_swid_set; 2248c2ecf20Sopenharmony_ci } 2258c2ecf20Sopenharmony_ci 2268c2ecf20Sopenharmony_ci /* Expose the IB port number as it's front panel name */ 2278c2ecf20Sopenharmony_ci err = mlxsw_sib_port_set(mlxsw_sib_port, module + 1); 2288c2ecf20Sopenharmony_ci if (err) { 2298c2ecf20Sopenharmony_ci dev_err(mlxsw_sib->bus_info->dev, "Port %d: Failed to set IB port\n", 2308c2ecf20Sopenharmony_ci mlxsw_sib_port->local_port); 2318c2ecf20Sopenharmony_ci goto err_port_ib_set; 2328c2ecf20Sopenharmony_ci } 2338c2ecf20Sopenharmony_ci 2348c2ecf20Sopenharmony_ci /* Supports all speeds from SDR to FDR (bitmask) and support bus width 2358c2ecf20Sopenharmony_ci * of 1x, 2x and 4x (3 bits bitmask) 2368c2ecf20Sopenharmony_ci */ 2378c2ecf20Sopenharmony_ci err = mlxsw_sib_port_speed_set(mlxsw_sib_port, 2388c2ecf20Sopenharmony_ci MLXSW_REG_PTYS_IB_SPEED_EDR - 1, 2398c2ecf20Sopenharmony_ci BIT(3) - 1); 2408c2ecf20Sopenharmony_ci if (err) { 2418c2ecf20Sopenharmony_ci dev_err(mlxsw_sib->bus_info->dev, "Port %d: Failed to set speed\n", 2428c2ecf20Sopenharmony_ci mlxsw_sib_port->local_port); 2438c2ecf20Sopenharmony_ci goto err_port_speed_set; 2448c2ecf20Sopenharmony_ci } 2458c2ecf20Sopenharmony_ci 2468c2ecf20Sopenharmony_ci /* Change to the maximum MTU the device supports, the SMA will take 2478c2ecf20Sopenharmony_ci * care of the active MTU 2488c2ecf20Sopenharmony_ci */ 2498c2ecf20Sopenharmony_ci err = mlxsw_sib_port_mtu_set(mlxsw_sib_port, MLXSW_IB_DEFAULT_MTU); 2508c2ecf20Sopenharmony_ci if (err) { 2518c2ecf20Sopenharmony_ci dev_err(mlxsw_sib->bus_info->dev, "Port %d: Failed to set MTU\n", 2528c2ecf20Sopenharmony_ci mlxsw_sib_port->local_port); 2538c2ecf20Sopenharmony_ci goto err_port_mtu_set; 2548c2ecf20Sopenharmony_ci } 2558c2ecf20Sopenharmony_ci 2568c2ecf20Sopenharmony_ci err = mlxsw_sib_port_admin_status_set(mlxsw_sib_port, true); 2578c2ecf20Sopenharmony_ci if (err) { 2588c2ecf20Sopenharmony_ci dev_err(mlxsw_sib->bus_info->dev, "Port %d: Failed to change admin state to UP\n", 2598c2ecf20Sopenharmony_ci mlxsw_sib_port->local_port); 2608c2ecf20Sopenharmony_ci goto err_port_admin_set; 2618c2ecf20Sopenharmony_ci } 2628c2ecf20Sopenharmony_ci 2638c2ecf20Sopenharmony_ci mlxsw_core_port_ib_set(mlxsw_sib->core, mlxsw_sib_port->local_port, 2648c2ecf20Sopenharmony_ci mlxsw_sib_port); 2658c2ecf20Sopenharmony_ci mlxsw_sib->ports[local_port] = mlxsw_sib_port; 2668c2ecf20Sopenharmony_ci return 0; 2678c2ecf20Sopenharmony_ci 2688c2ecf20Sopenharmony_cierr_port_admin_set: 2698c2ecf20Sopenharmony_cierr_port_mtu_set: 2708c2ecf20Sopenharmony_cierr_port_speed_set: 2718c2ecf20Sopenharmony_cierr_port_ib_set: 2728c2ecf20Sopenharmony_ci mlxsw_sib_port_swid_set(mlxsw_sib_port, MLXSW_PORT_SWID_DISABLED_PORT); 2738c2ecf20Sopenharmony_cierr_port_swid_set: 2748c2ecf20Sopenharmony_ci kfree(mlxsw_sib_port); 2758c2ecf20Sopenharmony_ci return err; 2768c2ecf20Sopenharmony_ci} 2778c2ecf20Sopenharmony_ci 2788c2ecf20Sopenharmony_cistatic int mlxsw_sib_port_create(struct mlxsw_sib *mlxsw_sib, u8 local_port, 2798c2ecf20Sopenharmony_ci u8 module, u8 width) 2808c2ecf20Sopenharmony_ci{ 2818c2ecf20Sopenharmony_ci int err; 2828c2ecf20Sopenharmony_ci 2838c2ecf20Sopenharmony_ci err = mlxsw_core_port_init(mlxsw_sib->core, local_port, 2848c2ecf20Sopenharmony_ci module + 1, false, 0, false, 0, 2858c2ecf20Sopenharmony_ci mlxsw_sib->hw_id, sizeof(mlxsw_sib->hw_id)); 2868c2ecf20Sopenharmony_ci if (err) { 2878c2ecf20Sopenharmony_ci dev_err(mlxsw_sib->bus_info->dev, "Port %d: Failed to init core port\n", 2888c2ecf20Sopenharmony_ci local_port); 2898c2ecf20Sopenharmony_ci return err; 2908c2ecf20Sopenharmony_ci } 2918c2ecf20Sopenharmony_ci err = __mlxsw_sib_port_create(mlxsw_sib, local_port, module, width); 2928c2ecf20Sopenharmony_ci if (err) 2938c2ecf20Sopenharmony_ci goto err_port_create; 2948c2ecf20Sopenharmony_ci 2958c2ecf20Sopenharmony_ci return 0; 2968c2ecf20Sopenharmony_ci 2978c2ecf20Sopenharmony_cierr_port_create: 2988c2ecf20Sopenharmony_ci mlxsw_core_port_fini(mlxsw_sib->core, local_port); 2998c2ecf20Sopenharmony_ci return err; 3008c2ecf20Sopenharmony_ci} 3018c2ecf20Sopenharmony_ci 3028c2ecf20Sopenharmony_cistatic void __mlxsw_sib_port_remove(struct mlxsw_sib *mlxsw_sib, u8 local_port) 3038c2ecf20Sopenharmony_ci{ 3048c2ecf20Sopenharmony_ci struct mlxsw_sib_port *mlxsw_sib_port = mlxsw_sib->ports[local_port]; 3058c2ecf20Sopenharmony_ci 3068c2ecf20Sopenharmony_ci mlxsw_core_port_clear(mlxsw_sib->core, local_port, mlxsw_sib); 3078c2ecf20Sopenharmony_ci mlxsw_sib->ports[local_port] = NULL; 3088c2ecf20Sopenharmony_ci mlxsw_sib_port_admin_status_set(mlxsw_sib_port, false); 3098c2ecf20Sopenharmony_ci mlxsw_sib_port_swid_set(mlxsw_sib_port, MLXSW_PORT_SWID_DISABLED_PORT); 3108c2ecf20Sopenharmony_ci kfree(mlxsw_sib_port); 3118c2ecf20Sopenharmony_ci} 3128c2ecf20Sopenharmony_ci 3138c2ecf20Sopenharmony_cistatic void mlxsw_sib_port_remove(struct mlxsw_sib *mlxsw_sib, u8 local_port) 3148c2ecf20Sopenharmony_ci{ 3158c2ecf20Sopenharmony_ci __mlxsw_sib_port_remove(mlxsw_sib, local_port); 3168c2ecf20Sopenharmony_ci mlxsw_core_port_fini(mlxsw_sib->core, local_port); 3178c2ecf20Sopenharmony_ci} 3188c2ecf20Sopenharmony_ci 3198c2ecf20Sopenharmony_cistatic void mlxsw_sib_ports_remove(struct mlxsw_sib *mlxsw_sib) 3208c2ecf20Sopenharmony_ci{ 3218c2ecf20Sopenharmony_ci int i; 3228c2ecf20Sopenharmony_ci 3238c2ecf20Sopenharmony_ci for (i = 1; i < MLXSW_PORT_MAX_IB_PORTS; i++) 3248c2ecf20Sopenharmony_ci if (mlxsw_sib_port_created(mlxsw_sib, i)) 3258c2ecf20Sopenharmony_ci mlxsw_sib_port_remove(mlxsw_sib, i); 3268c2ecf20Sopenharmony_ci kfree(mlxsw_sib->ports); 3278c2ecf20Sopenharmony_ci} 3288c2ecf20Sopenharmony_ci 3298c2ecf20Sopenharmony_cistatic int mlxsw_sib_ports_create(struct mlxsw_sib *mlxsw_sib) 3308c2ecf20Sopenharmony_ci{ 3318c2ecf20Sopenharmony_ci size_t alloc_size; 3328c2ecf20Sopenharmony_ci u8 module, width; 3338c2ecf20Sopenharmony_ci int i; 3348c2ecf20Sopenharmony_ci int err; 3358c2ecf20Sopenharmony_ci 3368c2ecf20Sopenharmony_ci alloc_size = sizeof(struct mlxsw_sib_port *) * MLXSW_PORT_MAX_IB_PORTS; 3378c2ecf20Sopenharmony_ci mlxsw_sib->ports = kzalloc(alloc_size, GFP_KERNEL); 3388c2ecf20Sopenharmony_ci if (!mlxsw_sib->ports) 3398c2ecf20Sopenharmony_ci return -ENOMEM; 3408c2ecf20Sopenharmony_ci 3418c2ecf20Sopenharmony_ci for (i = 1; i < MLXSW_PORT_MAX_IB_PORTS; i++) { 3428c2ecf20Sopenharmony_ci err = mlxsw_sib_port_module_info_get(mlxsw_sib, i, &module, 3438c2ecf20Sopenharmony_ci &width); 3448c2ecf20Sopenharmony_ci if (err) 3458c2ecf20Sopenharmony_ci goto err_port_module_info_get; 3468c2ecf20Sopenharmony_ci if (!width) 3478c2ecf20Sopenharmony_ci continue; 3488c2ecf20Sopenharmony_ci err = mlxsw_sib_port_create(mlxsw_sib, i, module, width); 3498c2ecf20Sopenharmony_ci if (err) 3508c2ecf20Sopenharmony_ci goto err_port_create; 3518c2ecf20Sopenharmony_ci } 3528c2ecf20Sopenharmony_ci return 0; 3538c2ecf20Sopenharmony_ci 3548c2ecf20Sopenharmony_cierr_port_create: 3558c2ecf20Sopenharmony_cierr_port_module_info_get: 3568c2ecf20Sopenharmony_ci for (i--; i >= 1; i--) 3578c2ecf20Sopenharmony_ci if (mlxsw_sib_port_created(mlxsw_sib, i)) 3588c2ecf20Sopenharmony_ci mlxsw_sib_port_remove(mlxsw_sib, i); 3598c2ecf20Sopenharmony_ci kfree(mlxsw_sib->ports); 3608c2ecf20Sopenharmony_ci return err; 3618c2ecf20Sopenharmony_ci} 3628c2ecf20Sopenharmony_ci 3638c2ecf20Sopenharmony_cistatic void 3648c2ecf20Sopenharmony_cimlxsw_sib_pude_ib_event_func(struct mlxsw_sib_port *mlxsw_sib_port, 3658c2ecf20Sopenharmony_ci enum mlxsw_reg_pude_oper_status status) 3668c2ecf20Sopenharmony_ci{ 3678c2ecf20Sopenharmony_ci if (status == MLXSW_PORT_OPER_STATUS_UP) 3688c2ecf20Sopenharmony_ci pr_info("ib link for port %d - up\n", 3698c2ecf20Sopenharmony_ci mlxsw_sib_port->mapping.module + 1); 3708c2ecf20Sopenharmony_ci else 3718c2ecf20Sopenharmony_ci pr_info("ib link for port %d - down\n", 3728c2ecf20Sopenharmony_ci mlxsw_sib_port->mapping.module + 1); 3738c2ecf20Sopenharmony_ci} 3748c2ecf20Sopenharmony_ci 3758c2ecf20Sopenharmony_cistatic void mlxsw_sib_pude_event_func(const struct mlxsw_reg_info *reg, 3768c2ecf20Sopenharmony_ci char *pude_pl, void *priv) 3778c2ecf20Sopenharmony_ci{ 3788c2ecf20Sopenharmony_ci struct mlxsw_sib *mlxsw_sib = priv; 3798c2ecf20Sopenharmony_ci struct mlxsw_sib_port *mlxsw_sib_port; 3808c2ecf20Sopenharmony_ci enum mlxsw_reg_pude_oper_status status; 3818c2ecf20Sopenharmony_ci u8 local_port; 3828c2ecf20Sopenharmony_ci 3838c2ecf20Sopenharmony_ci local_port = mlxsw_reg_pude_local_port_get(pude_pl); 3848c2ecf20Sopenharmony_ci mlxsw_sib_port = mlxsw_sib->ports[local_port]; 3858c2ecf20Sopenharmony_ci if (!mlxsw_sib_port) { 3868c2ecf20Sopenharmony_ci dev_warn(mlxsw_sib->bus_info->dev, "Port %d: Link event received for non-existent port\n", 3878c2ecf20Sopenharmony_ci local_port); 3888c2ecf20Sopenharmony_ci return; 3898c2ecf20Sopenharmony_ci } 3908c2ecf20Sopenharmony_ci 3918c2ecf20Sopenharmony_ci status = mlxsw_reg_pude_oper_status_get(pude_pl); 3928c2ecf20Sopenharmony_ci mlxsw_sib_pude_ib_event_func(mlxsw_sib_port, status); 3938c2ecf20Sopenharmony_ci} 3948c2ecf20Sopenharmony_ci 3958c2ecf20Sopenharmony_cistatic const struct mlxsw_listener mlxsw_sib_listener[] = { 3968c2ecf20Sopenharmony_ci MLXSW_EVENTL(mlxsw_sib_pude_event_func, PUDE, EMAD), 3978c2ecf20Sopenharmony_ci}; 3988c2ecf20Sopenharmony_ci 3998c2ecf20Sopenharmony_cistatic int mlxsw_sib_taps_init(struct mlxsw_sib *mlxsw_sib) 4008c2ecf20Sopenharmony_ci{ 4018c2ecf20Sopenharmony_ci int i; 4028c2ecf20Sopenharmony_ci int err; 4038c2ecf20Sopenharmony_ci 4048c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(mlxsw_sib_listener); i++) { 4058c2ecf20Sopenharmony_ci err = mlxsw_core_trap_register(mlxsw_sib->core, 4068c2ecf20Sopenharmony_ci &mlxsw_sib_listener[i], 4078c2ecf20Sopenharmony_ci mlxsw_sib); 4088c2ecf20Sopenharmony_ci if (err) 4098c2ecf20Sopenharmony_ci goto err_rx_listener_register; 4108c2ecf20Sopenharmony_ci } 4118c2ecf20Sopenharmony_ci 4128c2ecf20Sopenharmony_ci return 0; 4138c2ecf20Sopenharmony_ci 4148c2ecf20Sopenharmony_cierr_rx_listener_register: 4158c2ecf20Sopenharmony_ci for (i--; i >= 0; i--) { 4168c2ecf20Sopenharmony_ci mlxsw_core_trap_unregister(mlxsw_sib->core, 4178c2ecf20Sopenharmony_ci &mlxsw_sib_listener[i], 4188c2ecf20Sopenharmony_ci mlxsw_sib); 4198c2ecf20Sopenharmony_ci } 4208c2ecf20Sopenharmony_ci 4218c2ecf20Sopenharmony_ci return err; 4228c2ecf20Sopenharmony_ci} 4238c2ecf20Sopenharmony_ci 4248c2ecf20Sopenharmony_cistatic void mlxsw_sib_traps_fini(struct mlxsw_sib *mlxsw_sib) 4258c2ecf20Sopenharmony_ci{ 4268c2ecf20Sopenharmony_ci int i; 4278c2ecf20Sopenharmony_ci 4288c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(mlxsw_sib_listener); i++) { 4298c2ecf20Sopenharmony_ci mlxsw_core_trap_unregister(mlxsw_sib->core, 4308c2ecf20Sopenharmony_ci &mlxsw_sib_listener[i], mlxsw_sib); 4318c2ecf20Sopenharmony_ci } 4328c2ecf20Sopenharmony_ci} 4338c2ecf20Sopenharmony_ci 4348c2ecf20Sopenharmony_cistatic int mlxsw_sib_basic_trap_groups_set(struct mlxsw_core *mlxsw_core) 4358c2ecf20Sopenharmony_ci{ 4368c2ecf20Sopenharmony_ci char htgt_pl[MLXSW_REG_HTGT_LEN]; 4378c2ecf20Sopenharmony_ci 4388c2ecf20Sopenharmony_ci mlxsw_reg_htgt_pack(htgt_pl, MLXSW_REG_HTGT_TRAP_GROUP_EMAD, 4398c2ecf20Sopenharmony_ci MLXSW_REG_HTGT_INVALID_POLICER, 4408c2ecf20Sopenharmony_ci MLXSW_REG_HTGT_DEFAULT_PRIORITY, 4418c2ecf20Sopenharmony_ci MLXSW_REG_HTGT_DEFAULT_TC); 4428c2ecf20Sopenharmony_ci mlxsw_reg_htgt_swid_set(htgt_pl, MLXSW_PORT_SWID_ALL_SWIDS); 4438c2ecf20Sopenharmony_ci mlxsw_reg_htgt_local_path_rdq_set(htgt_pl, 4448c2ecf20Sopenharmony_ci MLXSW_REG_HTGT_LOCAL_PATH_RDQ_SIB_EMAD); 4458c2ecf20Sopenharmony_ci return mlxsw_reg_write(mlxsw_core, MLXSW_REG(htgt), htgt_pl); 4468c2ecf20Sopenharmony_ci} 4478c2ecf20Sopenharmony_ci 4488c2ecf20Sopenharmony_cistatic int mlxsw_sib_init(struct mlxsw_core *mlxsw_core, 4498c2ecf20Sopenharmony_ci const struct mlxsw_bus_info *mlxsw_bus_info, 4508c2ecf20Sopenharmony_ci struct netlink_ext_ack *extack) 4518c2ecf20Sopenharmony_ci{ 4528c2ecf20Sopenharmony_ci struct mlxsw_sib *mlxsw_sib = mlxsw_core_driver_priv(mlxsw_core); 4538c2ecf20Sopenharmony_ci int err; 4548c2ecf20Sopenharmony_ci 4558c2ecf20Sopenharmony_ci mlxsw_sib->core = mlxsw_core; 4568c2ecf20Sopenharmony_ci mlxsw_sib->bus_info = mlxsw_bus_info; 4578c2ecf20Sopenharmony_ci 4588c2ecf20Sopenharmony_ci err = mlxsw_sib_hw_id_get(mlxsw_sib); 4598c2ecf20Sopenharmony_ci if (err) { 4608c2ecf20Sopenharmony_ci dev_err(mlxsw_sib->bus_info->dev, "Failed to get switch HW ID\n"); 4618c2ecf20Sopenharmony_ci return err; 4628c2ecf20Sopenharmony_ci } 4638c2ecf20Sopenharmony_ci 4648c2ecf20Sopenharmony_ci err = mlxsw_sib_ports_create(mlxsw_sib); 4658c2ecf20Sopenharmony_ci if (err) { 4668c2ecf20Sopenharmony_ci dev_err(mlxsw_sib->bus_info->dev, "Failed to create ports\n"); 4678c2ecf20Sopenharmony_ci return err; 4688c2ecf20Sopenharmony_ci } 4698c2ecf20Sopenharmony_ci 4708c2ecf20Sopenharmony_ci err = mlxsw_sib_taps_init(mlxsw_sib); 4718c2ecf20Sopenharmony_ci if (err) { 4728c2ecf20Sopenharmony_ci dev_err(mlxsw_sib->bus_info->dev, "Failed to set traps\n"); 4738c2ecf20Sopenharmony_ci goto err_traps_init_err; 4748c2ecf20Sopenharmony_ci } 4758c2ecf20Sopenharmony_ci 4768c2ecf20Sopenharmony_ci return 0; 4778c2ecf20Sopenharmony_ci 4788c2ecf20Sopenharmony_cierr_traps_init_err: 4798c2ecf20Sopenharmony_ci mlxsw_sib_ports_remove(mlxsw_sib); 4808c2ecf20Sopenharmony_ci return err; 4818c2ecf20Sopenharmony_ci} 4828c2ecf20Sopenharmony_ci 4838c2ecf20Sopenharmony_cistatic void mlxsw_sib_fini(struct mlxsw_core *mlxsw_core) 4848c2ecf20Sopenharmony_ci{ 4858c2ecf20Sopenharmony_ci struct mlxsw_sib *mlxsw_sib = mlxsw_core_driver_priv(mlxsw_core); 4868c2ecf20Sopenharmony_ci 4878c2ecf20Sopenharmony_ci mlxsw_sib_traps_fini(mlxsw_sib); 4888c2ecf20Sopenharmony_ci mlxsw_sib_ports_remove(mlxsw_sib); 4898c2ecf20Sopenharmony_ci} 4908c2ecf20Sopenharmony_ci 4918c2ecf20Sopenharmony_cistatic const struct mlxsw_config_profile mlxsw_sib_config_profile = { 4928c2ecf20Sopenharmony_ci .used_max_system_port = 1, 4938c2ecf20Sopenharmony_ci .max_system_port = 48000, 4948c2ecf20Sopenharmony_ci .used_max_ib_mc = 1, 4958c2ecf20Sopenharmony_ci .max_ib_mc = 27, 4968c2ecf20Sopenharmony_ci .used_max_pkey = 1, 4978c2ecf20Sopenharmony_ci .max_pkey = 32, 4988c2ecf20Sopenharmony_ci .swid_config = { 4998c2ecf20Sopenharmony_ci { 5008c2ecf20Sopenharmony_ci .used_type = 1, 5018c2ecf20Sopenharmony_ci .type = MLXSW_PORT_SWID_TYPE_IB, 5028c2ecf20Sopenharmony_ci } 5038c2ecf20Sopenharmony_ci }, 5048c2ecf20Sopenharmony_ci}; 5058c2ecf20Sopenharmony_ci 5068c2ecf20Sopenharmony_cistatic struct mlxsw_driver mlxsw_sib_driver = { 5078c2ecf20Sopenharmony_ci .kind = mlxsw_sib_driver_name, 5088c2ecf20Sopenharmony_ci .priv_size = sizeof(struct mlxsw_sib), 5098c2ecf20Sopenharmony_ci .init = mlxsw_sib_init, 5108c2ecf20Sopenharmony_ci .fini = mlxsw_sib_fini, 5118c2ecf20Sopenharmony_ci .basic_trap_groups_set = mlxsw_sib_basic_trap_groups_set, 5128c2ecf20Sopenharmony_ci .txhdr_construct = mlxsw_sib_tx_v1_hdr_construct, 5138c2ecf20Sopenharmony_ci .txhdr_len = MLXSW_TXHDR_LEN, 5148c2ecf20Sopenharmony_ci .profile = &mlxsw_sib_config_profile, 5158c2ecf20Sopenharmony_ci}; 5168c2ecf20Sopenharmony_ci 5178c2ecf20Sopenharmony_cistatic struct mlxsw_driver mlxsw_sib2_driver = { 5188c2ecf20Sopenharmony_ci .kind = mlxsw_sib2_driver_name, 5198c2ecf20Sopenharmony_ci .priv_size = sizeof(struct mlxsw_sib), 5208c2ecf20Sopenharmony_ci .init = mlxsw_sib_init, 5218c2ecf20Sopenharmony_ci .fini = mlxsw_sib_fini, 5228c2ecf20Sopenharmony_ci .basic_trap_groups_set = mlxsw_sib_basic_trap_groups_set, 5238c2ecf20Sopenharmony_ci .txhdr_construct = mlxsw_sib_tx_v1_hdr_construct, 5248c2ecf20Sopenharmony_ci .txhdr_len = MLXSW_TXHDR_LEN, 5258c2ecf20Sopenharmony_ci .profile = &mlxsw_sib_config_profile, 5268c2ecf20Sopenharmony_ci}; 5278c2ecf20Sopenharmony_ci 5288c2ecf20Sopenharmony_cistatic const struct pci_device_id mlxsw_sib_pci_id_table[] = { 5298c2ecf20Sopenharmony_ci {PCI_VDEVICE(MELLANOX, PCI_DEVICE_ID_MELLANOX_SWITCHIB), 0}, 5308c2ecf20Sopenharmony_ci {0, }, 5318c2ecf20Sopenharmony_ci}; 5328c2ecf20Sopenharmony_ci 5338c2ecf20Sopenharmony_cistatic struct pci_driver mlxsw_sib_pci_driver = { 5348c2ecf20Sopenharmony_ci .name = mlxsw_sib_driver_name, 5358c2ecf20Sopenharmony_ci .id_table = mlxsw_sib_pci_id_table, 5368c2ecf20Sopenharmony_ci}; 5378c2ecf20Sopenharmony_ci 5388c2ecf20Sopenharmony_cistatic const struct pci_device_id mlxsw_sib2_pci_id_table[] = { 5398c2ecf20Sopenharmony_ci {PCI_VDEVICE(MELLANOX, PCI_DEVICE_ID_MELLANOX_SWITCHIB2), 0}, 5408c2ecf20Sopenharmony_ci {0, }, 5418c2ecf20Sopenharmony_ci}; 5428c2ecf20Sopenharmony_ci 5438c2ecf20Sopenharmony_cistatic struct pci_driver mlxsw_sib2_pci_driver = { 5448c2ecf20Sopenharmony_ci .name = mlxsw_sib2_driver_name, 5458c2ecf20Sopenharmony_ci .id_table = mlxsw_sib2_pci_id_table, 5468c2ecf20Sopenharmony_ci}; 5478c2ecf20Sopenharmony_ci 5488c2ecf20Sopenharmony_cistatic int __init mlxsw_sib_module_init(void) 5498c2ecf20Sopenharmony_ci{ 5508c2ecf20Sopenharmony_ci int err; 5518c2ecf20Sopenharmony_ci 5528c2ecf20Sopenharmony_ci err = mlxsw_core_driver_register(&mlxsw_sib_driver); 5538c2ecf20Sopenharmony_ci if (err) 5548c2ecf20Sopenharmony_ci return err; 5558c2ecf20Sopenharmony_ci 5568c2ecf20Sopenharmony_ci err = mlxsw_core_driver_register(&mlxsw_sib2_driver); 5578c2ecf20Sopenharmony_ci if (err) 5588c2ecf20Sopenharmony_ci goto err_sib2_driver_register; 5598c2ecf20Sopenharmony_ci 5608c2ecf20Sopenharmony_ci err = mlxsw_pci_driver_register(&mlxsw_sib_pci_driver); 5618c2ecf20Sopenharmony_ci if (err) 5628c2ecf20Sopenharmony_ci goto err_sib_pci_driver_register; 5638c2ecf20Sopenharmony_ci 5648c2ecf20Sopenharmony_ci err = mlxsw_pci_driver_register(&mlxsw_sib2_pci_driver); 5658c2ecf20Sopenharmony_ci if (err) 5668c2ecf20Sopenharmony_ci goto err_sib2_pci_driver_register; 5678c2ecf20Sopenharmony_ci 5688c2ecf20Sopenharmony_ci return 0; 5698c2ecf20Sopenharmony_ci 5708c2ecf20Sopenharmony_cierr_sib2_pci_driver_register: 5718c2ecf20Sopenharmony_ci mlxsw_pci_driver_unregister(&mlxsw_sib_pci_driver); 5728c2ecf20Sopenharmony_cierr_sib_pci_driver_register: 5738c2ecf20Sopenharmony_ci mlxsw_core_driver_unregister(&mlxsw_sib2_driver); 5748c2ecf20Sopenharmony_cierr_sib2_driver_register: 5758c2ecf20Sopenharmony_ci mlxsw_core_driver_unregister(&mlxsw_sib_driver); 5768c2ecf20Sopenharmony_ci return err; 5778c2ecf20Sopenharmony_ci} 5788c2ecf20Sopenharmony_ci 5798c2ecf20Sopenharmony_cistatic void __exit mlxsw_sib_module_exit(void) 5808c2ecf20Sopenharmony_ci{ 5818c2ecf20Sopenharmony_ci mlxsw_pci_driver_unregister(&mlxsw_sib2_pci_driver); 5828c2ecf20Sopenharmony_ci mlxsw_pci_driver_unregister(&mlxsw_sib_pci_driver); 5838c2ecf20Sopenharmony_ci mlxsw_core_driver_unregister(&mlxsw_sib2_driver); 5848c2ecf20Sopenharmony_ci mlxsw_core_driver_unregister(&mlxsw_sib_driver); 5858c2ecf20Sopenharmony_ci} 5868c2ecf20Sopenharmony_ci 5878c2ecf20Sopenharmony_cimodule_init(mlxsw_sib_module_init); 5888c2ecf20Sopenharmony_cimodule_exit(mlxsw_sib_module_exit); 5898c2ecf20Sopenharmony_ci 5908c2ecf20Sopenharmony_ciMODULE_LICENSE("Dual BSD/GPL"); 5918c2ecf20Sopenharmony_ciMODULE_AUTHOR("Elad Raz <eladr@@mellanox.com>"); 5928c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Mellanox SwitchIB and SwitchIB-2 driver"); 5938c2ecf20Sopenharmony_ciMODULE_ALIAS("mlxsw_switchib2"); 5948c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(pci, mlxsw_sib_pci_id_table); 5958c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(pci, mlxsw_sib2_pci_id_table); 596