core.c (95381B)
1// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0 2/* Copyright (c) 2015-2018 Mellanox Technologies. All rights reserved */ 3 4#include <linux/kernel.h> 5#include <linux/module.h> 6#include <linux/device.h> 7#include <linux/export.h> 8#include <linux/err.h> 9#include <linux/if_link.h> 10#include <linux/netdevice.h> 11#include <linux/completion.h> 12#include <linux/skbuff.h> 13#include <linux/etherdevice.h> 14#include <linux/types.h> 15#include <linux/string.h> 16#include <linux/gfp.h> 17#include <linux/random.h> 18#include <linux/jiffies.h> 19#include <linux/mutex.h> 20#include <linux/rcupdate.h> 21#include <linux/slab.h> 22#include <linux/workqueue.h> 23#include <linux/firmware.h> 24#include <asm/byteorder.h> 25#include <net/devlink.h> 26#include <trace/events/devlink.h> 27 28#include "core.h" 29#include "core_env.h" 30#include "item.h" 31#include "cmd.h" 32#include "port.h" 33#include "trap.h" 34#include "emad.h" 35#include "reg.h" 36#include "resources.h" 37#include "../mlxfw/mlxfw.h" 38 39static LIST_HEAD(mlxsw_core_driver_list); 40static DEFINE_SPINLOCK(mlxsw_core_driver_list_lock); 41 42static const char mlxsw_core_driver_name[] = "mlxsw_core"; 43 44static struct workqueue_struct *mlxsw_wq; 45static struct workqueue_struct *mlxsw_owq; 46 47struct mlxsw_core_port { 48 struct devlink_port devlink_port; 49 void *port_driver_priv; 50 u16 local_port; 51 struct mlxsw_linecard *linecard; 52}; 53 54void *mlxsw_core_port_driver_priv(struct mlxsw_core_port *mlxsw_core_port) 55{ 56 return mlxsw_core_port->port_driver_priv; 57} 58EXPORT_SYMBOL(mlxsw_core_port_driver_priv); 59 60static bool mlxsw_core_port_check(struct mlxsw_core_port *mlxsw_core_port) 61{ 62 return mlxsw_core_port->port_driver_priv != NULL; 63} 64 65struct mlxsw_core { 66 struct mlxsw_driver *driver; 67 const struct mlxsw_bus *bus; 68 void *bus_priv; 69 const struct mlxsw_bus_info *bus_info; 70 struct workqueue_struct *emad_wq; 71 struct list_head rx_listener_list; 72 struct list_head event_listener_list; 73 struct { 74 atomic64_t tid; 75 struct list_head trans_list; 76 spinlock_t trans_list_lock; /* protects trans_list writes */ 77 bool use_emad; 78 bool enable_string_tlv; 79 } emad; 80 struct { 81 u16 *mapping; /* lag_id+port_index to local_port mapping */ 82 } lag; 83 struct mlxsw_res res; 84 struct mlxsw_hwmon *hwmon; 85 struct mlxsw_thermal *thermal; 86 struct mlxsw_linecards *linecards; 87 struct mlxsw_core_port *ports; 88 unsigned int max_ports; 89 atomic_t active_ports_count; 90 bool fw_flash_in_progress; 91 struct { 92 struct devlink_health_reporter *fw_fatal; 93 } health; 94 struct mlxsw_env *env; 95 unsigned long driver_priv[]; 96 /* driver_priv has to be always the last item */ 97}; 98 99struct mlxsw_linecards *mlxsw_core_linecards(struct mlxsw_core *mlxsw_core) 100{ 101 return mlxsw_core->linecards; 102} 103 104void mlxsw_core_linecards_set(struct mlxsw_core *mlxsw_core, 105 struct mlxsw_linecards *linecards) 106{ 107 mlxsw_core->linecards = linecards; 108} 109 110#define MLXSW_PORT_MAX_PORTS_DEFAULT 0x40 111 112static u64 mlxsw_ports_occ_get(void *priv) 113{ 114 struct mlxsw_core *mlxsw_core = priv; 115 116 return atomic_read(&mlxsw_core->active_ports_count); 117} 118 119static int mlxsw_core_resources_ports_register(struct mlxsw_core *mlxsw_core) 120{ 121 struct devlink *devlink = priv_to_devlink(mlxsw_core); 122 struct devlink_resource_size_params ports_num_params; 123 u32 max_ports; 124 125 max_ports = mlxsw_core->max_ports - 1; 126 devlink_resource_size_params_init(&ports_num_params, max_ports, 127 max_ports, 1, 128 DEVLINK_RESOURCE_UNIT_ENTRY); 129 130 return devlink_resource_register(devlink, 131 DEVLINK_RESOURCE_GENERIC_NAME_PORTS, 132 max_ports, MLXSW_CORE_RESOURCE_PORTS, 133 DEVLINK_RESOURCE_ID_PARENT_TOP, 134 &ports_num_params); 135} 136 137static int mlxsw_ports_init(struct mlxsw_core *mlxsw_core, bool reload) 138{ 139 struct devlink *devlink = priv_to_devlink(mlxsw_core); 140 int err; 141 142 /* Switch ports are numbered from 1 to queried value */ 143 if (MLXSW_CORE_RES_VALID(mlxsw_core, MAX_SYSTEM_PORT)) 144 mlxsw_core->max_ports = MLXSW_CORE_RES_GET(mlxsw_core, 145 MAX_SYSTEM_PORT) + 1; 146 else 147 mlxsw_core->max_ports = MLXSW_PORT_MAX_PORTS_DEFAULT + 1; 148 149 mlxsw_core->ports = kcalloc(mlxsw_core->max_ports, 150 sizeof(struct mlxsw_core_port), GFP_KERNEL); 151 if (!mlxsw_core->ports) 152 return -ENOMEM; 153 154 if (!reload) { 155 err = mlxsw_core_resources_ports_register(mlxsw_core); 156 if (err) 157 goto err_resources_ports_register; 158 } 159 atomic_set(&mlxsw_core->active_ports_count, 0); 160 devlink_resource_occ_get_register(devlink, MLXSW_CORE_RESOURCE_PORTS, 161 mlxsw_ports_occ_get, mlxsw_core); 162 163 return 0; 164 165err_resources_ports_register: 166 kfree(mlxsw_core->ports); 167 return err; 168} 169 170static void mlxsw_ports_fini(struct mlxsw_core *mlxsw_core, bool reload) 171{ 172 struct devlink *devlink = priv_to_devlink(mlxsw_core); 173 174 devlink_resource_occ_get_unregister(devlink, MLXSW_CORE_RESOURCE_PORTS); 175 if (!reload) 176 devlink_resources_unregister(priv_to_devlink(mlxsw_core)); 177 178 kfree(mlxsw_core->ports); 179} 180 181unsigned int mlxsw_core_max_ports(const struct mlxsw_core *mlxsw_core) 182{ 183 return mlxsw_core->max_ports; 184} 185EXPORT_SYMBOL(mlxsw_core_max_ports); 186 187void *mlxsw_core_driver_priv(struct mlxsw_core *mlxsw_core) 188{ 189 return mlxsw_core->driver_priv; 190} 191EXPORT_SYMBOL(mlxsw_core_driver_priv); 192 193bool 194mlxsw_core_fw_rev_minor_subminor_validate(const struct mlxsw_fw_rev *rev, 195 const struct mlxsw_fw_rev *req_rev) 196{ 197 return rev->minor > req_rev->minor || 198 (rev->minor == req_rev->minor && 199 rev->subminor >= req_rev->subminor); 200} 201EXPORT_SYMBOL(mlxsw_core_fw_rev_minor_subminor_validate); 202 203struct mlxsw_rx_listener_item { 204 struct list_head list; 205 struct mlxsw_rx_listener rxl; 206 void *priv; 207 bool enabled; 208}; 209 210struct mlxsw_event_listener_item { 211 struct list_head list; 212 struct mlxsw_core *mlxsw_core; 213 struct mlxsw_event_listener el; 214 void *priv; 215}; 216 217static const u8 mlxsw_core_trap_groups[] = { 218 MLXSW_REG_HTGT_TRAP_GROUP_EMAD, 219 MLXSW_REG_HTGT_TRAP_GROUP_CORE_EVENT, 220}; 221 222static int mlxsw_core_trap_groups_set(struct mlxsw_core *mlxsw_core) 223{ 224 char htgt_pl[MLXSW_REG_HTGT_LEN]; 225 int err; 226 int i; 227 228 if (!(mlxsw_core->bus->features & MLXSW_BUS_F_TXRX)) 229 return 0; 230 231 for (i = 0; i < ARRAY_SIZE(mlxsw_core_trap_groups); i++) { 232 mlxsw_reg_htgt_pack(htgt_pl, mlxsw_core_trap_groups[i], 233 MLXSW_REG_HTGT_INVALID_POLICER, 234 MLXSW_REG_HTGT_DEFAULT_PRIORITY, 235 MLXSW_REG_HTGT_DEFAULT_TC); 236 err = mlxsw_reg_write(mlxsw_core, MLXSW_REG(htgt), htgt_pl); 237 if (err) 238 return err; 239 } 240 return 0; 241} 242 243/****************** 244 * EMAD processing 245 ******************/ 246 247/* emad_eth_hdr_dmac 248 * Destination MAC in EMAD's Ethernet header. 249 * Must be set to 01:02:c9:00:00:01 250 */ 251MLXSW_ITEM_BUF(emad, eth_hdr, dmac, 0x00, 6); 252 253/* emad_eth_hdr_smac 254 * Source MAC in EMAD's Ethernet header. 255 * Must be set to 00:02:c9:01:02:03 256 */ 257MLXSW_ITEM_BUF(emad, eth_hdr, smac, 0x06, 6); 258 259/* emad_eth_hdr_ethertype 260 * Ethertype in EMAD's Ethernet header. 261 * Must be set to 0x8932 262 */ 263MLXSW_ITEM32(emad, eth_hdr, ethertype, 0x0C, 16, 16); 264 265/* emad_eth_hdr_mlx_proto 266 * Mellanox protocol. 267 * Must be set to 0x0. 268 */ 269MLXSW_ITEM32(emad, eth_hdr, mlx_proto, 0x0C, 8, 8); 270 271/* emad_eth_hdr_ver 272 * Mellanox protocol version. 273 * Must be set to 0x0. 274 */ 275MLXSW_ITEM32(emad, eth_hdr, ver, 0x0C, 4, 4); 276 277/* emad_op_tlv_type 278 * Type of the TLV. 279 * Must be set to 0x1 (operation TLV). 280 */ 281MLXSW_ITEM32(emad, op_tlv, type, 0x00, 27, 5); 282 283/* emad_op_tlv_len 284 * Length of the operation TLV in u32. 285 * Must be set to 0x4. 286 */ 287MLXSW_ITEM32(emad, op_tlv, len, 0x00, 16, 11); 288 289/* emad_op_tlv_dr 290 * Direct route bit. Setting to 1 indicates the EMAD is a direct route 291 * EMAD. DR TLV must follow. 292 * 293 * Note: Currently not supported and must not be set. 294 */ 295MLXSW_ITEM32(emad, op_tlv, dr, 0x00, 15, 1); 296 297/* emad_op_tlv_status 298 * Returned status in case of EMAD response. Must be set to 0 in case 299 * of EMAD request. 300 * 0x0 - success 301 * 0x1 - device is busy. Requester should retry 302 * 0x2 - Mellanox protocol version not supported 303 * 0x3 - unknown TLV 304 * 0x4 - register not supported 305 * 0x5 - operation class not supported 306 * 0x6 - EMAD method not supported 307 * 0x7 - bad parameter (e.g. port out of range) 308 * 0x8 - resource not available 309 * 0x9 - message receipt acknowledgment. Requester should retry 310 * 0x70 - internal error 311 */ 312MLXSW_ITEM32(emad, op_tlv, status, 0x00, 8, 7); 313 314/* emad_op_tlv_register_id 315 * Register ID of register within register TLV. 316 */ 317MLXSW_ITEM32(emad, op_tlv, register_id, 0x04, 16, 16); 318 319/* emad_op_tlv_r 320 * Response bit. Setting to 1 indicates Response, otherwise request. 321 */ 322MLXSW_ITEM32(emad, op_tlv, r, 0x04, 15, 1); 323 324/* emad_op_tlv_method 325 * EMAD method type. 326 * 0x1 - query 327 * 0x2 - write 328 * 0x3 - send (currently not supported) 329 * 0x4 - event 330 */ 331MLXSW_ITEM32(emad, op_tlv, method, 0x04, 8, 7); 332 333/* emad_op_tlv_class 334 * EMAD operation class. Must be set to 0x1 (REG_ACCESS). 335 */ 336MLXSW_ITEM32(emad, op_tlv, class, 0x04, 0, 8); 337 338/* emad_op_tlv_tid 339 * EMAD transaction ID. Used for pairing request and response EMADs. 340 */ 341MLXSW_ITEM64(emad, op_tlv, tid, 0x08, 0, 64); 342 343/* emad_string_tlv_type 344 * Type of the TLV. 345 * Must be set to 0x2 (string TLV). 346 */ 347MLXSW_ITEM32(emad, string_tlv, type, 0x00, 27, 5); 348 349/* emad_string_tlv_len 350 * Length of the string TLV in u32. 351 */ 352MLXSW_ITEM32(emad, string_tlv, len, 0x00, 16, 11); 353 354#define MLXSW_EMAD_STRING_TLV_STRING_LEN 128 355 356/* emad_string_tlv_string 357 * String provided by the device's firmware in case of erroneous register access 358 */ 359MLXSW_ITEM_BUF(emad, string_tlv, string, 0x04, 360 MLXSW_EMAD_STRING_TLV_STRING_LEN); 361 362/* emad_reg_tlv_type 363 * Type of the TLV. 364 * Must be set to 0x3 (register TLV). 365 */ 366MLXSW_ITEM32(emad, reg_tlv, type, 0x00, 27, 5); 367 368/* emad_reg_tlv_len 369 * Length of the operation TLV in u32. 370 */ 371MLXSW_ITEM32(emad, reg_tlv, len, 0x00, 16, 11); 372 373/* emad_end_tlv_type 374 * Type of the TLV. 375 * Must be set to 0x0 (end TLV). 376 */ 377MLXSW_ITEM32(emad, end_tlv, type, 0x00, 27, 5); 378 379/* emad_end_tlv_len 380 * Length of the end TLV in u32. 381 * Must be set to 1. 382 */ 383MLXSW_ITEM32(emad, end_tlv, len, 0x00, 16, 11); 384 385enum mlxsw_core_reg_access_type { 386 MLXSW_CORE_REG_ACCESS_TYPE_QUERY, 387 MLXSW_CORE_REG_ACCESS_TYPE_WRITE, 388}; 389 390static inline const char * 391mlxsw_core_reg_access_type_str(enum mlxsw_core_reg_access_type type) 392{ 393 switch (type) { 394 case MLXSW_CORE_REG_ACCESS_TYPE_QUERY: 395 return "query"; 396 case MLXSW_CORE_REG_ACCESS_TYPE_WRITE: 397 return "write"; 398 } 399 BUG(); 400} 401 402static void mlxsw_emad_pack_end_tlv(char *end_tlv) 403{ 404 mlxsw_emad_end_tlv_type_set(end_tlv, MLXSW_EMAD_TLV_TYPE_END); 405 mlxsw_emad_end_tlv_len_set(end_tlv, MLXSW_EMAD_END_TLV_LEN); 406} 407 408static void mlxsw_emad_pack_reg_tlv(char *reg_tlv, 409 const struct mlxsw_reg_info *reg, 410 char *payload) 411{ 412 mlxsw_emad_reg_tlv_type_set(reg_tlv, MLXSW_EMAD_TLV_TYPE_REG); 413 mlxsw_emad_reg_tlv_len_set(reg_tlv, reg->len / sizeof(u32) + 1); 414 memcpy(reg_tlv + sizeof(u32), payload, reg->len); 415} 416 417static void mlxsw_emad_pack_string_tlv(char *string_tlv) 418{ 419 mlxsw_emad_string_tlv_type_set(string_tlv, MLXSW_EMAD_TLV_TYPE_STRING); 420 mlxsw_emad_string_tlv_len_set(string_tlv, MLXSW_EMAD_STRING_TLV_LEN); 421} 422 423static void mlxsw_emad_pack_op_tlv(char *op_tlv, 424 const struct mlxsw_reg_info *reg, 425 enum mlxsw_core_reg_access_type type, 426 u64 tid) 427{ 428 mlxsw_emad_op_tlv_type_set(op_tlv, MLXSW_EMAD_TLV_TYPE_OP); 429 mlxsw_emad_op_tlv_len_set(op_tlv, MLXSW_EMAD_OP_TLV_LEN); 430 mlxsw_emad_op_tlv_dr_set(op_tlv, 0); 431 mlxsw_emad_op_tlv_status_set(op_tlv, 0); 432 mlxsw_emad_op_tlv_register_id_set(op_tlv, reg->id); 433 mlxsw_emad_op_tlv_r_set(op_tlv, MLXSW_EMAD_OP_TLV_REQUEST); 434 if (type == MLXSW_CORE_REG_ACCESS_TYPE_QUERY) 435 mlxsw_emad_op_tlv_method_set(op_tlv, 436 MLXSW_EMAD_OP_TLV_METHOD_QUERY); 437 else 438 mlxsw_emad_op_tlv_method_set(op_tlv, 439 MLXSW_EMAD_OP_TLV_METHOD_WRITE); 440 mlxsw_emad_op_tlv_class_set(op_tlv, 441 MLXSW_EMAD_OP_TLV_CLASS_REG_ACCESS); 442 mlxsw_emad_op_tlv_tid_set(op_tlv, tid); 443} 444 445static int mlxsw_emad_construct_eth_hdr(struct sk_buff *skb) 446{ 447 char *eth_hdr = skb_push(skb, MLXSW_EMAD_ETH_HDR_LEN); 448 449 mlxsw_emad_eth_hdr_dmac_memcpy_to(eth_hdr, MLXSW_EMAD_EH_DMAC); 450 mlxsw_emad_eth_hdr_smac_memcpy_to(eth_hdr, MLXSW_EMAD_EH_SMAC); 451 mlxsw_emad_eth_hdr_ethertype_set(eth_hdr, MLXSW_EMAD_EH_ETHERTYPE); 452 mlxsw_emad_eth_hdr_mlx_proto_set(eth_hdr, MLXSW_EMAD_EH_MLX_PROTO); 453 mlxsw_emad_eth_hdr_ver_set(eth_hdr, MLXSW_EMAD_EH_PROTO_VERSION); 454 455 skb_reset_mac_header(skb); 456 457 return 0; 458} 459 460static void mlxsw_emad_construct(struct sk_buff *skb, 461 const struct mlxsw_reg_info *reg, 462 char *payload, 463 enum mlxsw_core_reg_access_type type, 464 u64 tid, bool enable_string_tlv) 465{ 466 char *buf; 467 468 buf = skb_push(skb, MLXSW_EMAD_END_TLV_LEN * sizeof(u32)); 469 mlxsw_emad_pack_end_tlv(buf); 470 471 buf = skb_push(skb, reg->len + sizeof(u32)); 472 mlxsw_emad_pack_reg_tlv(buf, reg, payload); 473 474 if (enable_string_tlv) { 475 buf = skb_push(skb, MLXSW_EMAD_STRING_TLV_LEN * sizeof(u32)); 476 mlxsw_emad_pack_string_tlv(buf); 477 } 478 479 buf = skb_push(skb, MLXSW_EMAD_OP_TLV_LEN * sizeof(u32)); 480 mlxsw_emad_pack_op_tlv(buf, reg, type, tid); 481 482 mlxsw_emad_construct_eth_hdr(skb); 483} 484 485struct mlxsw_emad_tlv_offsets { 486 u16 op_tlv; 487 u16 string_tlv; 488 u16 reg_tlv; 489}; 490 491static bool mlxsw_emad_tlv_is_string_tlv(const char *tlv) 492{ 493 u8 tlv_type = mlxsw_emad_string_tlv_type_get(tlv); 494 495 return tlv_type == MLXSW_EMAD_TLV_TYPE_STRING; 496} 497 498static void mlxsw_emad_tlv_parse(struct sk_buff *skb) 499{ 500 struct mlxsw_emad_tlv_offsets *offsets = 501 (struct mlxsw_emad_tlv_offsets *) skb->cb; 502 503 offsets->op_tlv = MLXSW_EMAD_ETH_HDR_LEN; 504 offsets->string_tlv = 0; 505 offsets->reg_tlv = MLXSW_EMAD_ETH_HDR_LEN + 506 MLXSW_EMAD_OP_TLV_LEN * sizeof(u32); 507 508 /* If string TLV is present, it must come after the operation TLV. */ 509 if (mlxsw_emad_tlv_is_string_tlv(skb->data + offsets->reg_tlv)) { 510 offsets->string_tlv = offsets->reg_tlv; 511 offsets->reg_tlv += MLXSW_EMAD_STRING_TLV_LEN * sizeof(u32); 512 } 513} 514 515static char *mlxsw_emad_op_tlv(const struct sk_buff *skb) 516{ 517 struct mlxsw_emad_tlv_offsets *offsets = 518 (struct mlxsw_emad_tlv_offsets *) skb->cb; 519 520 return ((char *) (skb->data + offsets->op_tlv)); 521} 522 523static char *mlxsw_emad_string_tlv(const struct sk_buff *skb) 524{ 525 struct mlxsw_emad_tlv_offsets *offsets = 526 (struct mlxsw_emad_tlv_offsets *) skb->cb; 527 528 if (!offsets->string_tlv) 529 return NULL; 530 531 return ((char *) (skb->data + offsets->string_tlv)); 532} 533 534static char *mlxsw_emad_reg_tlv(const struct sk_buff *skb) 535{ 536 struct mlxsw_emad_tlv_offsets *offsets = 537 (struct mlxsw_emad_tlv_offsets *) skb->cb; 538 539 return ((char *) (skb->data + offsets->reg_tlv)); 540} 541 542static char *mlxsw_emad_reg_payload(const char *reg_tlv) 543{ 544 return ((char *) (reg_tlv + sizeof(u32))); 545} 546 547static char *mlxsw_emad_reg_payload_cmd(const char *mbox) 548{ 549 return ((char *) (mbox + (MLXSW_EMAD_OP_TLV_LEN + 1) * sizeof(u32))); 550} 551 552static u64 mlxsw_emad_get_tid(const struct sk_buff *skb) 553{ 554 char *op_tlv; 555 556 op_tlv = mlxsw_emad_op_tlv(skb); 557 return mlxsw_emad_op_tlv_tid_get(op_tlv); 558} 559 560static bool mlxsw_emad_is_resp(const struct sk_buff *skb) 561{ 562 char *op_tlv; 563 564 op_tlv = mlxsw_emad_op_tlv(skb); 565 return (mlxsw_emad_op_tlv_r_get(op_tlv) == MLXSW_EMAD_OP_TLV_RESPONSE); 566} 567 568static int mlxsw_emad_process_status(char *op_tlv, 569 enum mlxsw_emad_op_tlv_status *p_status) 570{ 571 *p_status = mlxsw_emad_op_tlv_status_get(op_tlv); 572 573 switch (*p_status) { 574 case MLXSW_EMAD_OP_TLV_STATUS_SUCCESS: 575 return 0; 576 case MLXSW_EMAD_OP_TLV_STATUS_BUSY: 577 case MLXSW_EMAD_OP_TLV_STATUS_MESSAGE_RECEIPT_ACK: 578 return -EAGAIN; 579 case MLXSW_EMAD_OP_TLV_STATUS_VERSION_NOT_SUPPORTED: 580 case MLXSW_EMAD_OP_TLV_STATUS_UNKNOWN_TLV: 581 case MLXSW_EMAD_OP_TLV_STATUS_REGISTER_NOT_SUPPORTED: 582 case MLXSW_EMAD_OP_TLV_STATUS_CLASS_NOT_SUPPORTED: 583 case MLXSW_EMAD_OP_TLV_STATUS_METHOD_NOT_SUPPORTED: 584 case MLXSW_EMAD_OP_TLV_STATUS_BAD_PARAMETER: 585 case MLXSW_EMAD_OP_TLV_STATUS_RESOURCE_NOT_AVAILABLE: 586 case MLXSW_EMAD_OP_TLV_STATUS_INTERNAL_ERROR: 587 default: 588 return -EIO; 589 } 590} 591 592static int 593mlxsw_emad_process_status_skb(struct sk_buff *skb, 594 enum mlxsw_emad_op_tlv_status *p_status) 595{ 596 return mlxsw_emad_process_status(mlxsw_emad_op_tlv(skb), p_status); 597} 598 599struct mlxsw_reg_trans { 600 struct list_head list; 601 struct list_head bulk_list; 602 struct mlxsw_core *core; 603 struct sk_buff *tx_skb; 604 struct mlxsw_tx_info tx_info; 605 struct delayed_work timeout_dw; 606 unsigned int retries; 607 u64 tid; 608 struct completion completion; 609 atomic_t active; 610 mlxsw_reg_trans_cb_t *cb; 611 unsigned long cb_priv; 612 const struct mlxsw_reg_info *reg; 613 enum mlxsw_core_reg_access_type type; 614 int err; 615 char *emad_err_string; 616 enum mlxsw_emad_op_tlv_status emad_status; 617 struct rcu_head rcu; 618}; 619 620static void mlxsw_emad_process_string_tlv(const struct sk_buff *skb, 621 struct mlxsw_reg_trans *trans) 622{ 623 char *string_tlv; 624 char *string; 625 626 string_tlv = mlxsw_emad_string_tlv(skb); 627 if (!string_tlv) 628 return; 629 630 trans->emad_err_string = kzalloc(MLXSW_EMAD_STRING_TLV_STRING_LEN, 631 GFP_ATOMIC); 632 if (!trans->emad_err_string) 633 return; 634 635 string = mlxsw_emad_string_tlv_string_data(string_tlv); 636 strlcpy(trans->emad_err_string, string, 637 MLXSW_EMAD_STRING_TLV_STRING_LEN); 638} 639 640#define MLXSW_EMAD_TIMEOUT_DURING_FW_FLASH_MS 3000 641#define MLXSW_EMAD_TIMEOUT_MS 200 642 643static void mlxsw_emad_trans_timeout_schedule(struct mlxsw_reg_trans *trans) 644{ 645 unsigned long timeout = msecs_to_jiffies(MLXSW_EMAD_TIMEOUT_MS); 646 647 if (trans->core->fw_flash_in_progress) 648 timeout = msecs_to_jiffies(MLXSW_EMAD_TIMEOUT_DURING_FW_FLASH_MS); 649 650 queue_delayed_work(trans->core->emad_wq, &trans->timeout_dw, 651 timeout << trans->retries); 652} 653 654static int mlxsw_emad_transmit(struct mlxsw_core *mlxsw_core, 655 struct mlxsw_reg_trans *trans) 656{ 657 struct sk_buff *skb; 658 int err; 659 660 skb = skb_clone(trans->tx_skb, GFP_KERNEL); 661 if (!skb) 662 return -ENOMEM; 663 664 trace_devlink_hwmsg(priv_to_devlink(mlxsw_core), false, 0, 665 skb->data + mlxsw_core->driver->txhdr_len, 666 skb->len - mlxsw_core->driver->txhdr_len); 667 668 atomic_set(&trans->active, 1); 669 err = mlxsw_core_skb_transmit(mlxsw_core, skb, &trans->tx_info); 670 if (err) { 671 dev_kfree_skb(skb); 672 return err; 673 } 674 mlxsw_emad_trans_timeout_schedule(trans); 675 return 0; 676} 677 678static void mlxsw_emad_trans_finish(struct mlxsw_reg_trans *trans, int err) 679{ 680 struct mlxsw_core *mlxsw_core = trans->core; 681 682 dev_kfree_skb(trans->tx_skb); 683 spin_lock_bh(&mlxsw_core->emad.trans_list_lock); 684 list_del_rcu(&trans->list); 685 spin_unlock_bh(&mlxsw_core->emad.trans_list_lock); 686 trans->err = err; 687 complete(&trans->completion); 688} 689 690static void mlxsw_emad_transmit_retry(struct mlxsw_core *mlxsw_core, 691 struct mlxsw_reg_trans *trans) 692{ 693 int err; 694 695 if (trans->retries < MLXSW_EMAD_MAX_RETRY) { 696 trans->retries++; 697 err = mlxsw_emad_transmit(trans->core, trans); 698 if (err == 0) 699 return; 700 701 if (!atomic_dec_and_test(&trans->active)) 702 return; 703 } else { 704 err = -EIO; 705 } 706 mlxsw_emad_trans_finish(trans, err); 707} 708 709static void mlxsw_emad_trans_timeout_work(struct work_struct *work) 710{ 711 struct mlxsw_reg_trans *trans = container_of(work, 712 struct mlxsw_reg_trans, 713 timeout_dw.work); 714 715 if (!atomic_dec_and_test(&trans->active)) 716 return; 717 718 mlxsw_emad_transmit_retry(trans->core, trans); 719} 720 721static void mlxsw_emad_process_response(struct mlxsw_core *mlxsw_core, 722 struct mlxsw_reg_trans *trans, 723 struct sk_buff *skb) 724{ 725 int err; 726 727 if (!atomic_dec_and_test(&trans->active)) 728 return; 729 730 err = mlxsw_emad_process_status_skb(skb, &trans->emad_status); 731 if (err == -EAGAIN) { 732 mlxsw_emad_transmit_retry(mlxsw_core, trans); 733 } else { 734 if (err == 0) { 735 char *reg_tlv = mlxsw_emad_reg_tlv(skb); 736 737 if (trans->cb) 738 trans->cb(mlxsw_core, 739 mlxsw_emad_reg_payload(reg_tlv), 740 trans->reg->len, trans->cb_priv); 741 } else { 742 mlxsw_emad_process_string_tlv(skb, trans); 743 } 744 mlxsw_emad_trans_finish(trans, err); 745 } 746} 747 748/* called with rcu read lock held */ 749static void mlxsw_emad_rx_listener_func(struct sk_buff *skb, u16 local_port, 750 void *priv) 751{ 752 struct mlxsw_core *mlxsw_core = priv; 753 struct mlxsw_reg_trans *trans; 754 755 trace_devlink_hwmsg(priv_to_devlink(mlxsw_core), true, 0, 756 skb->data, skb->len); 757 758 mlxsw_emad_tlv_parse(skb); 759 760 if (!mlxsw_emad_is_resp(skb)) 761 goto free_skb; 762 763 list_for_each_entry_rcu(trans, &mlxsw_core->emad.trans_list, list) { 764 if (mlxsw_emad_get_tid(skb) == trans->tid) { 765 mlxsw_emad_process_response(mlxsw_core, trans, skb); 766 break; 767 } 768 } 769 770free_skb: 771 dev_kfree_skb(skb); 772} 773 774static const struct mlxsw_listener mlxsw_emad_rx_listener = 775 MLXSW_RXL(mlxsw_emad_rx_listener_func, ETHEMAD, TRAP_TO_CPU, false, 776 EMAD, DISCARD); 777 778static int mlxsw_emad_init(struct mlxsw_core *mlxsw_core) 779{ 780 struct workqueue_struct *emad_wq; 781 u64 tid; 782 int err; 783 784 if (!(mlxsw_core->bus->features & MLXSW_BUS_F_TXRX)) 785 return 0; 786 787 emad_wq = alloc_workqueue("mlxsw_core_emad", 0, 0); 788 if (!emad_wq) 789 return -ENOMEM; 790 mlxsw_core->emad_wq = emad_wq; 791 792 /* Set the upper 32 bits of the transaction ID field to a random 793 * number. This allows us to discard EMADs addressed to other 794 * devices. 795 */ 796 get_random_bytes(&tid, 4); 797 tid <<= 32; 798 atomic64_set(&mlxsw_core->emad.tid, tid); 799 800 INIT_LIST_HEAD(&mlxsw_core->emad.trans_list); 801 spin_lock_init(&mlxsw_core->emad.trans_list_lock); 802 803 err = mlxsw_core_trap_register(mlxsw_core, &mlxsw_emad_rx_listener, 804 mlxsw_core); 805 if (err) 806 goto err_trap_register; 807 808 mlxsw_core->emad.use_emad = true; 809 810 return 0; 811 812err_trap_register: 813 destroy_workqueue(mlxsw_core->emad_wq); 814 return err; 815} 816 817static void mlxsw_emad_fini(struct mlxsw_core *mlxsw_core) 818{ 819 820 if (!(mlxsw_core->bus->features & MLXSW_BUS_F_TXRX)) 821 return; 822 823 mlxsw_core->emad.use_emad = false; 824 mlxsw_core_trap_unregister(mlxsw_core, &mlxsw_emad_rx_listener, 825 mlxsw_core); 826 destroy_workqueue(mlxsw_core->emad_wq); 827} 828 829static struct sk_buff *mlxsw_emad_alloc(const struct mlxsw_core *mlxsw_core, 830 u16 reg_len, bool enable_string_tlv) 831{ 832 struct sk_buff *skb; 833 u16 emad_len; 834 835 emad_len = (reg_len + sizeof(u32) + MLXSW_EMAD_ETH_HDR_LEN + 836 (MLXSW_EMAD_OP_TLV_LEN + MLXSW_EMAD_END_TLV_LEN) * 837 sizeof(u32) + mlxsw_core->driver->txhdr_len); 838 if (enable_string_tlv) 839 emad_len += MLXSW_EMAD_STRING_TLV_LEN * sizeof(u32); 840 if (emad_len > MLXSW_EMAD_MAX_FRAME_LEN) 841 return NULL; 842 843 skb = netdev_alloc_skb(NULL, emad_len); 844 if (!skb) 845 return NULL; 846 memset(skb->data, 0, emad_len); 847 skb_reserve(skb, emad_len); 848 849 return skb; 850} 851 852static int mlxsw_emad_reg_access(struct mlxsw_core *mlxsw_core, 853 const struct mlxsw_reg_info *reg, 854 char *payload, 855 enum mlxsw_core_reg_access_type type, 856 struct mlxsw_reg_trans *trans, 857 struct list_head *bulk_list, 858 mlxsw_reg_trans_cb_t *cb, 859 unsigned long cb_priv, u64 tid) 860{ 861 bool enable_string_tlv; 862 struct sk_buff *skb; 863 int err; 864 865 dev_dbg(mlxsw_core->bus_info->dev, "EMAD reg access (tid=%llx,reg_id=%x(%s),type=%s)\n", 866 tid, reg->id, mlxsw_reg_id_str(reg->id), 867 mlxsw_core_reg_access_type_str(type)); 868 869 /* Since this can be changed during emad_reg_access, read it once and 870 * use the value all the way. 871 */ 872 enable_string_tlv = mlxsw_core->emad.enable_string_tlv; 873 874 skb = mlxsw_emad_alloc(mlxsw_core, reg->len, enable_string_tlv); 875 if (!skb) 876 return -ENOMEM; 877 878 list_add_tail(&trans->bulk_list, bulk_list); 879 trans->core = mlxsw_core; 880 trans->tx_skb = skb; 881 trans->tx_info.local_port = MLXSW_PORT_CPU_PORT; 882 trans->tx_info.is_emad = true; 883 INIT_DELAYED_WORK(&trans->timeout_dw, mlxsw_emad_trans_timeout_work); 884 trans->tid = tid; 885 init_completion(&trans->completion); 886 trans->cb = cb; 887 trans->cb_priv = cb_priv; 888 trans->reg = reg; 889 trans->type = type; 890 891 mlxsw_emad_construct(skb, reg, payload, type, trans->tid, 892 enable_string_tlv); 893 mlxsw_core->driver->txhdr_construct(skb, &trans->tx_info); 894 895 spin_lock_bh(&mlxsw_core->emad.trans_list_lock); 896 list_add_tail_rcu(&trans->list, &mlxsw_core->emad.trans_list); 897 spin_unlock_bh(&mlxsw_core->emad.trans_list_lock); 898 err = mlxsw_emad_transmit(mlxsw_core, trans); 899 if (err) 900 goto err_out; 901 return 0; 902 903err_out: 904 spin_lock_bh(&mlxsw_core->emad.trans_list_lock); 905 list_del_rcu(&trans->list); 906 spin_unlock_bh(&mlxsw_core->emad.trans_list_lock); 907 list_del(&trans->bulk_list); 908 dev_kfree_skb(trans->tx_skb); 909 return err; 910} 911 912/***************** 913 * Core functions 914 *****************/ 915 916int mlxsw_core_driver_register(struct mlxsw_driver *mlxsw_driver) 917{ 918 spin_lock(&mlxsw_core_driver_list_lock); 919 list_add_tail(&mlxsw_driver->list, &mlxsw_core_driver_list); 920 spin_unlock(&mlxsw_core_driver_list_lock); 921 return 0; 922} 923EXPORT_SYMBOL(mlxsw_core_driver_register); 924 925void mlxsw_core_driver_unregister(struct mlxsw_driver *mlxsw_driver) 926{ 927 spin_lock(&mlxsw_core_driver_list_lock); 928 list_del(&mlxsw_driver->list); 929 spin_unlock(&mlxsw_core_driver_list_lock); 930} 931EXPORT_SYMBOL(mlxsw_core_driver_unregister); 932 933static struct mlxsw_driver *__driver_find(const char *kind) 934{ 935 struct mlxsw_driver *mlxsw_driver; 936 937 list_for_each_entry(mlxsw_driver, &mlxsw_core_driver_list, list) { 938 if (strcmp(mlxsw_driver->kind, kind) == 0) 939 return mlxsw_driver; 940 } 941 return NULL; 942} 943 944static struct mlxsw_driver *mlxsw_core_driver_get(const char *kind) 945{ 946 struct mlxsw_driver *mlxsw_driver; 947 948 spin_lock(&mlxsw_core_driver_list_lock); 949 mlxsw_driver = __driver_find(kind); 950 spin_unlock(&mlxsw_core_driver_list_lock); 951 return mlxsw_driver; 952} 953 954struct mlxsw_core_fw_info { 955 struct mlxfw_dev mlxfw_dev; 956 struct mlxsw_core *mlxsw_core; 957}; 958 959static int mlxsw_core_fw_component_query(struct mlxfw_dev *mlxfw_dev, 960 u16 component_index, u32 *p_max_size, 961 u8 *p_align_bits, u16 *p_max_write_size) 962{ 963 struct mlxsw_core_fw_info *mlxsw_core_fw_info = 964 container_of(mlxfw_dev, struct mlxsw_core_fw_info, mlxfw_dev); 965 struct mlxsw_core *mlxsw_core = mlxsw_core_fw_info->mlxsw_core; 966 char mcqi_pl[MLXSW_REG_MCQI_LEN]; 967 int err; 968 969 mlxsw_reg_mcqi_pack(mcqi_pl, component_index); 970 err = mlxsw_reg_query(mlxsw_core, MLXSW_REG(mcqi), mcqi_pl); 971 if (err) 972 return err; 973 mlxsw_reg_mcqi_unpack(mcqi_pl, p_max_size, p_align_bits, p_max_write_size); 974 975 *p_align_bits = max_t(u8, *p_align_bits, 2); 976 *p_max_write_size = min_t(u16, *p_max_write_size, MLXSW_REG_MCDA_MAX_DATA_LEN); 977 return 0; 978} 979 980static int mlxsw_core_fw_fsm_lock(struct mlxfw_dev *mlxfw_dev, u32 *fwhandle) 981{ 982 struct mlxsw_core_fw_info *mlxsw_core_fw_info = 983 container_of(mlxfw_dev, struct mlxsw_core_fw_info, mlxfw_dev); 984 struct mlxsw_core *mlxsw_core = mlxsw_core_fw_info->mlxsw_core; 985 char mcc_pl[MLXSW_REG_MCC_LEN]; 986 u8 control_state; 987 int err; 988 989 mlxsw_reg_mcc_pack(mcc_pl, 0, 0, 0, 0); 990 err = mlxsw_reg_query(mlxsw_core, MLXSW_REG(mcc), mcc_pl); 991 if (err) 992 return err; 993 994 mlxsw_reg_mcc_unpack(mcc_pl, fwhandle, NULL, &control_state); 995 if (control_state != MLXFW_FSM_STATE_IDLE) 996 return -EBUSY; 997 998 mlxsw_reg_mcc_pack(mcc_pl, MLXSW_REG_MCC_INSTRUCTION_LOCK_UPDATE_HANDLE, 0, *fwhandle, 0); 999 return mlxsw_reg_write(mlxsw_core, MLXSW_REG(mcc), mcc_pl); 1000} 1001 1002static int mlxsw_core_fw_fsm_component_update(struct mlxfw_dev *mlxfw_dev, u32 fwhandle, 1003 u16 component_index, u32 component_size) 1004{ 1005 struct mlxsw_core_fw_info *mlxsw_core_fw_info = 1006 container_of(mlxfw_dev, struct mlxsw_core_fw_info, mlxfw_dev); 1007 struct mlxsw_core *mlxsw_core = mlxsw_core_fw_info->mlxsw_core; 1008 char mcc_pl[MLXSW_REG_MCC_LEN]; 1009 1010 mlxsw_reg_mcc_pack(mcc_pl, MLXSW_REG_MCC_INSTRUCTION_UPDATE_COMPONENT, 1011 component_index, fwhandle, component_size); 1012 return mlxsw_reg_write(mlxsw_core, MLXSW_REG(mcc), mcc_pl); 1013} 1014 1015static int mlxsw_core_fw_fsm_block_download(struct mlxfw_dev *mlxfw_dev, u32 fwhandle, 1016 u8 *data, u16 size, u32 offset) 1017{ 1018 struct mlxsw_core_fw_info *mlxsw_core_fw_info = 1019 container_of(mlxfw_dev, struct mlxsw_core_fw_info, mlxfw_dev); 1020 struct mlxsw_core *mlxsw_core = mlxsw_core_fw_info->mlxsw_core; 1021 char mcda_pl[MLXSW_REG_MCDA_LEN]; 1022 1023 mlxsw_reg_mcda_pack(mcda_pl, fwhandle, offset, size, data); 1024 return mlxsw_reg_write(mlxsw_core, MLXSW_REG(mcda), mcda_pl); 1025} 1026 1027static int mlxsw_core_fw_fsm_component_verify(struct mlxfw_dev *mlxfw_dev, u32 fwhandle, 1028 u16 component_index) 1029{ 1030 struct mlxsw_core_fw_info *mlxsw_core_fw_info = 1031 container_of(mlxfw_dev, struct mlxsw_core_fw_info, mlxfw_dev); 1032 struct mlxsw_core *mlxsw_core = mlxsw_core_fw_info->mlxsw_core; 1033 char mcc_pl[MLXSW_REG_MCC_LEN]; 1034 1035 mlxsw_reg_mcc_pack(mcc_pl, MLXSW_REG_MCC_INSTRUCTION_VERIFY_COMPONENT, 1036 component_index, fwhandle, 0); 1037 return mlxsw_reg_write(mlxsw_core, MLXSW_REG(mcc), mcc_pl); 1038} 1039 1040static int mlxsw_core_fw_fsm_activate(struct mlxfw_dev *mlxfw_dev, u32 fwhandle) 1041{ 1042 struct mlxsw_core_fw_info *mlxsw_core_fw_info = 1043 container_of(mlxfw_dev, struct mlxsw_core_fw_info, mlxfw_dev); 1044 struct mlxsw_core *mlxsw_core = mlxsw_core_fw_info->mlxsw_core; 1045 char mcc_pl[MLXSW_REG_MCC_LEN]; 1046 1047 mlxsw_reg_mcc_pack(mcc_pl, MLXSW_REG_MCC_INSTRUCTION_ACTIVATE, 0, fwhandle, 0); 1048 return mlxsw_reg_write(mlxsw_core, MLXSW_REG(mcc), mcc_pl); 1049} 1050 1051static int mlxsw_core_fw_fsm_query_state(struct mlxfw_dev *mlxfw_dev, u32 fwhandle, 1052 enum mlxfw_fsm_state *fsm_state, 1053 enum mlxfw_fsm_state_err *fsm_state_err) 1054{ 1055 struct mlxsw_core_fw_info *mlxsw_core_fw_info = 1056 container_of(mlxfw_dev, struct mlxsw_core_fw_info, mlxfw_dev); 1057 struct mlxsw_core *mlxsw_core = mlxsw_core_fw_info->mlxsw_core; 1058 char mcc_pl[MLXSW_REG_MCC_LEN]; 1059 u8 control_state; 1060 u8 error_code; 1061 int err; 1062 1063 mlxsw_reg_mcc_pack(mcc_pl, 0, 0, fwhandle, 0); 1064 err = mlxsw_reg_query(mlxsw_core, MLXSW_REG(mcc), mcc_pl); 1065 if (err) 1066 return err; 1067 1068 mlxsw_reg_mcc_unpack(mcc_pl, NULL, &error_code, &control_state); 1069 *fsm_state = control_state; 1070 *fsm_state_err = min_t(enum mlxfw_fsm_state_err, error_code, MLXFW_FSM_STATE_ERR_MAX); 1071 return 0; 1072} 1073 1074static void mlxsw_core_fw_fsm_cancel(struct mlxfw_dev *mlxfw_dev, u32 fwhandle) 1075{ 1076 struct mlxsw_core_fw_info *mlxsw_core_fw_info = 1077 container_of(mlxfw_dev, struct mlxsw_core_fw_info, mlxfw_dev); 1078 struct mlxsw_core *mlxsw_core = mlxsw_core_fw_info->mlxsw_core; 1079 char mcc_pl[MLXSW_REG_MCC_LEN]; 1080 1081 mlxsw_reg_mcc_pack(mcc_pl, MLXSW_REG_MCC_INSTRUCTION_CANCEL, 0, fwhandle, 0); 1082 mlxsw_reg_write(mlxsw_core, MLXSW_REG(mcc), mcc_pl); 1083} 1084 1085static void mlxsw_core_fw_fsm_release(struct mlxfw_dev *mlxfw_dev, u32 fwhandle) 1086{ 1087 struct mlxsw_core_fw_info *mlxsw_core_fw_info = 1088 container_of(mlxfw_dev, struct mlxsw_core_fw_info, mlxfw_dev); 1089 struct mlxsw_core *mlxsw_core = mlxsw_core_fw_info->mlxsw_core; 1090 char mcc_pl[MLXSW_REG_MCC_LEN]; 1091 1092 mlxsw_reg_mcc_pack(mcc_pl, MLXSW_REG_MCC_INSTRUCTION_RELEASE_UPDATE_HANDLE, 0, fwhandle, 0); 1093 mlxsw_reg_write(mlxsw_core, MLXSW_REG(mcc), mcc_pl); 1094} 1095 1096static const struct mlxfw_dev_ops mlxsw_core_fw_mlxsw_dev_ops = { 1097 .component_query = mlxsw_core_fw_component_query, 1098 .fsm_lock = mlxsw_core_fw_fsm_lock, 1099 .fsm_component_update = mlxsw_core_fw_fsm_component_update, 1100 .fsm_block_download = mlxsw_core_fw_fsm_block_download, 1101 .fsm_component_verify = mlxsw_core_fw_fsm_component_verify, 1102 .fsm_activate = mlxsw_core_fw_fsm_activate, 1103 .fsm_query_state = mlxsw_core_fw_fsm_query_state, 1104 .fsm_cancel = mlxsw_core_fw_fsm_cancel, 1105 .fsm_release = mlxsw_core_fw_fsm_release, 1106}; 1107 1108static int mlxsw_core_fw_flash(struct mlxsw_core *mlxsw_core, const struct firmware *firmware, 1109 struct netlink_ext_ack *extack) 1110{ 1111 struct mlxsw_core_fw_info mlxsw_core_fw_info = { 1112 .mlxfw_dev = { 1113 .ops = &mlxsw_core_fw_mlxsw_dev_ops, 1114 .psid = mlxsw_core->bus_info->psid, 1115 .psid_size = strlen(mlxsw_core->bus_info->psid), 1116 .devlink = priv_to_devlink(mlxsw_core), 1117 }, 1118 .mlxsw_core = mlxsw_core 1119 }; 1120 int err; 1121 1122 mlxsw_core->fw_flash_in_progress = true; 1123 err = mlxfw_firmware_flash(&mlxsw_core_fw_info.mlxfw_dev, firmware, extack); 1124 mlxsw_core->fw_flash_in_progress = false; 1125 1126 return err; 1127} 1128 1129static int mlxsw_core_fw_rev_validate(struct mlxsw_core *mlxsw_core, 1130 const struct mlxsw_bus_info *mlxsw_bus_info, 1131 const struct mlxsw_fw_rev *req_rev, 1132 const char *filename) 1133{ 1134 const struct mlxsw_fw_rev *rev = &mlxsw_bus_info->fw_rev; 1135 union devlink_param_value value; 1136 const struct firmware *firmware; 1137 int err; 1138 1139 /* Don't check if driver does not require it */ 1140 if (!req_rev || !filename) 1141 return 0; 1142 1143 /* Don't check if devlink 'fw_load_policy' param is 'flash' */ 1144 err = devlink_param_driverinit_value_get(priv_to_devlink(mlxsw_core), 1145 DEVLINK_PARAM_GENERIC_ID_FW_LOAD_POLICY, 1146 &value); 1147 if (err) 1148 return err; 1149 if (value.vu8 == DEVLINK_PARAM_FW_LOAD_POLICY_VALUE_FLASH) 1150 return 0; 1151 1152 /* Validate driver & FW are compatible */ 1153 if (rev->major != req_rev->major) { 1154 WARN(1, "Mismatch in major FW version [%d:%d] is never expected; Please contact support\n", 1155 rev->major, req_rev->major); 1156 return -EINVAL; 1157 } 1158 if (mlxsw_core_fw_rev_minor_subminor_validate(rev, req_rev)) 1159 return 0; 1160 1161 dev_err(mlxsw_bus_info->dev, "The firmware version %d.%d.%d is incompatible with the driver (required >= %d.%d.%d)\n", 1162 rev->major, rev->minor, rev->subminor, req_rev->major, 1163 req_rev->minor, req_rev->subminor); 1164 dev_info(mlxsw_bus_info->dev, "Flashing firmware using file %s\n", filename); 1165 1166 err = request_firmware_direct(&firmware, filename, mlxsw_bus_info->dev); 1167 if (err) { 1168 dev_err(mlxsw_bus_info->dev, "Could not request firmware file %s\n", filename); 1169 return err; 1170 } 1171 1172 err = mlxsw_core_fw_flash(mlxsw_core, firmware, NULL); 1173 release_firmware(firmware); 1174 if (err) 1175 dev_err(mlxsw_bus_info->dev, "Could not upgrade firmware\n"); 1176 1177 /* On FW flash success, tell the caller FW reset is needed 1178 * if current FW supports it. 1179 */ 1180 if (rev->minor >= req_rev->can_reset_minor) 1181 return err ? err : -EAGAIN; 1182 else 1183 return 0; 1184} 1185 1186static int mlxsw_core_fw_flash_update(struct mlxsw_core *mlxsw_core, 1187 struct devlink_flash_update_params *params, 1188 struct netlink_ext_ack *extack) 1189{ 1190 return mlxsw_core_fw_flash(mlxsw_core, params->fw, extack); 1191} 1192 1193static int mlxsw_core_devlink_param_fw_load_policy_validate(struct devlink *devlink, u32 id, 1194 union devlink_param_value val, 1195 struct netlink_ext_ack *extack) 1196{ 1197 if (val.vu8 != DEVLINK_PARAM_FW_LOAD_POLICY_VALUE_DRIVER && 1198 val.vu8 != DEVLINK_PARAM_FW_LOAD_POLICY_VALUE_FLASH) { 1199 NL_SET_ERR_MSG_MOD(extack, "'fw_load_policy' must be 'driver' or 'flash'"); 1200 return -EINVAL; 1201 } 1202 1203 return 0; 1204} 1205 1206static const struct devlink_param mlxsw_core_fw_devlink_params[] = { 1207 DEVLINK_PARAM_GENERIC(FW_LOAD_POLICY, BIT(DEVLINK_PARAM_CMODE_DRIVERINIT), NULL, NULL, 1208 mlxsw_core_devlink_param_fw_load_policy_validate), 1209}; 1210 1211static int mlxsw_core_fw_params_register(struct mlxsw_core *mlxsw_core) 1212{ 1213 struct devlink *devlink = priv_to_devlink(mlxsw_core); 1214 union devlink_param_value value; 1215 int err; 1216 1217 err = devlink_params_register(devlink, mlxsw_core_fw_devlink_params, 1218 ARRAY_SIZE(mlxsw_core_fw_devlink_params)); 1219 if (err) 1220 return err; 1221 1222 value.vu8 = DEVLINK_PARAM_FW_LOAD_POLICY_VALUE_DRIVER; 1223 devlink_param_driverinit_value_set(devlink, DEVLINK_PARAM_GENERIC_ID_FW_LOAD_POLICY, value); 1224 return 0; 1225} 1226 1227static void mlxsw_core_fw_params_unregister(struct mlxsw_core *mlxsw_core) 1228{ 1229 devlink_params_unregister(priv_to_devlink(mlxsw_core), mlxsw_core_fw_devlink_params, 1230 ARRAY_SIZE(mlxsw_core_fw_devlink_params)); 1231} 1232 1233static void *__dl_port(struct devlink_port *devlink_port) 1234{ 1235 return container_of(devlink_port, struct mlxsw_core_port, devlink_port); 1236} 1237 1238static int mlxsw_devlink_port_split(struct devlink *devlink, 1239 struct devlink_port *port, 1240 unsigned int count, 1241 struct netlink_ext_ack *extack) 1242{ 1243 struct mlxsw_core_port *mlxsw_core_port = __dl_port(port); 1244 struct mlxsw_core *mlxsw_core = devlink_priv(devlink); 1245 1246 if (!mlxsw_core->driver->port_split) 1247 return -EOPNOTSUPP; 1248 return mlxsw_core->driver->port_split(mlxsw_core, 1249 mlxsw_core_port->local_port, 1250 count, extack); 1251} 1252 1253static int mlxsw_devlink_port_unsplit(struct devlink *devlink, 1254 struct devlink_port *port, 1255 struct netlink_ext_ack *extack) 1256{ 1257 struct mlxsw_core_port *mlxsw_core_port = __dl_port(port); 1258 struct mlxsw_core *mlxsw_core = devlink_priv(devlink); 1259 1260 if (!mlxsw_core->driver->port_unsplit) 1261 return -EOPNOTSUPP; 1262 return mlxsw_core->driver->port_unsplit(mlxsw_core, 1263 mlxsw_core_port->local_port, 1264 extack); 1265} 1266 1267static int 1268mlxsw_devlink_sb_pool_get(struct devlink *devlink, 1269 unsigned int sb_index, u16 pool_index, 1270 struct devlink_sb_pool_info *pool_info) 1271{ 1272 struct mlxsw_core *mlxsw_core = devlink_priv(devlink); 1273 struct mlxsw_driver *mlxsw_driver = mlxsw_core->driver; 1274 1275 if (!mlxsw_driver->sb_pool_get) 1276 return -EOPNOTSUPP; 1277 return mlxsw_driver->sb_pool_get(mlxsw_core, sb_index, 1278 pool_index, pool_info); 1279} 1280 1281static int 1282mlxsw_devlink_sb_pool_set(struct devlink *devlink, 1283 unsigned int sb_index, u16 pool_index, u32 size, 1284 enum devlink_sb_threshold_type threshold_type, 1285 struct netlink_ext_ack *extack) 1286{ 1287 struct mlxsw_core *mlxsw_core = devlink_priv(devlink); 1288 struct mlxsw_driver *mlxsw_driver = mlxsw_core->driver; 1289 1290 if (!mlxsw_driver->sb_pool_set) 1291 return -EOPNOTSUPP; 1292 return mlxsw_driver->sb_pool_set(mlxsw_core, sb_index, 1293 pool_index, size, threshold_type, 1294 extack); 1295} 1296 1297static int mlxsw_devlink_port_type_set(struct devlink_port *devlink_port, 1298 enum devlink_port_type port_type) 1299{ 1300 struct mlxsw_core *mlxsw_core = devlink_priv(devlink_port->devlink); 1301 struct mlxsw_driver *mlxsw_driver = mlxsw_core->driver; 1302 struct mlxsw_core_port *mlxsw_core_port = __dl_port(devlink_port); 1303 1304 if (!mlxsw_driver->port_type_set) 1305 return -EOPNOTSUPP; 1306 1307 return mlxsw_driver->port_type_set(mlxsw_core, 1308 mlxsw_core_port->local_port, 1309 port_type); 1310} 1311 1312static int mlxsw_devlink_sb_port_pool_get(struct devlink_port *devlink_port, 1313 unsigned int sb_index, u16 pool_index, 1314 u32 *p_threshold) 1315{ 1316 struct mlxsw_core *mlxsw_core = devlink_priv(devlink_port->devlink); 1317 struct mlxsw_driver *mlxsw_driver = mlxsw_core->driver; 1318 struct mlxsw_core_port *mlxsw_core_port = __dl_port(devlink_port); 1319 1320 if (!mlxsw_driver->sb_port_pool_get || 1321 !mlxsw_core_port_check(mlxsw_core_port)) 1322 return -EOPNOTSUPP; 1323 return mlxsw_driver->sb_port_pool_get(mlxsw_core_port, sb_index, 1324 pool_index, p_threshold); 1325} 1326 1327static int mlxsw_devlink_sb_port_pool_set(struct devlink_port *devlink_port, 1328 unsigned int sb_index, u16 pool_index, 1329 u32 threshold, 1330 struct netlink_ext_ack *extack) 1331{ 1332 struct mlxsw_core *mlxsw_core = devlink_priv(devlink_port->devlink); 1333 struct mlxsw_driver *mlxsw_driver = mlxsw_core->driver; 1334 struct mlxsw_core_port *mlxsw_core_port = __dl_port(devlink_port); 1335 1336 if (!mlxsw_driver->sb_port_pool_set || 1337 !mlxsw_core_port_check(mlxsw_core_port)) 1338 return -EOPNOTSUPP; 1339 return mlxsw_driver->sb_port_pool_set(mlxsw_core_port, sb_index, 1340 pool_index, threshold, extack); 1341} 1342 1343static int 1344mlxsw_devlink_sb_tc_pool_bind_get(struct devlink_port *devlink_port, 1345 unsigned int sb_index, u16 tc_index, 1346 enum devlink_sb_pool_type pool_type, 1347 u16 *p_pool_index, u32 *p_threshold) 1348{ 1349 struct mlxsw_core *mlxsw_core = devlink_priv(devlink_port->devlink); 1350 struct mlxsw_driver *mlxsw_driver = mlxsw_core->driver; 1351 struct mlxsw_core_port *mlxsw_core_port = __dl_port(devlink_port); 1352 1353 if (!mlxsw_driver->sb_tc_pool_bind_get || 1354 !mlxsw_core_port_check(mlxsw_core_port)) 1355 return -EOPNOTSUPP; 1356 return mlxsw_driver->sb_tc_pool_bind_get(mlxsw_core_port, sb_index, 1357 tc_index, pool_type, 1358 p_pool_index, p_threshold); 1359} 1360 1361static int 1362mlxsw_devlink_sb_tc_pool_bind_set(struct devlink_port *devlink_port, 1363 unsigned int sb_index, u16 tc_index, 1364 enum devlink_sb_pool_type pool_type, 1365 u16 pool_index, u32 threshold, 1366 struct netlink_ext_ack *extack) 1367{ 1368 struct mlxsw_core *mlxsw_core = devlink_priv(devlink_port->devlink); 1369 struct mlxsw_driver *mlxsw_driver = mlxsw_core->driver; 1370 struct mlxsw_core_port *mlxsw_core_port = __dl_port(devlink_port); 1371 1372 if (!mlxsw_driver->sb_tc_pool_bind_set || 1373 !mlxsw_core_port_check(mlxsw_core_port)) 1374 return -EOPNOTSUPP; 1375 return mlxsw_driver->sb_tc_pool_bind_set(mlxsw_core_port, sb_index, 1376 tc_index, pool_type, 1377 pool_index, threshold, extack); 1378} 1379 1380static int mlxsw_devlink_sb_occ_snapshot(struct devlink *devlink, 1381 unsigned int sb_index) 1382{ 1383 struct mlxsw_core *mlxsw_core = devlink_priv(devlink); 1384 struct mlxsw_driver *mlxsw_driver = mlxsw_core->driver; 1385 1386 if (!mlxsw_driver->sb_occ_snapshot) 1387 return -EOPNOTSUPP; 1388 return mlxsw_driver->sb_occ_snapshot(mlxsw_core, sb_index); 1389} 1390 1391static int mlxsw_devlink_sb_occ_max_clear(struct devlink *devlink, 1392 unsigned int sb_index) 1393{ 1394 struct mlxsw_core *mlxsw_core = devlink_priv(devlink); 1395 struct mlxsw_driver *mlxsw_driver = mlxsw_core->driver; 1396 1397 if (!mlxsw_driver->sb_occ_max_clear) 1398 return -EOPNOTSUPP; 1399 return mlxsw_driver->sb_occ_max_clear(mlxsw_core, sb_index); 1400} 1401 1402static int 1403mlxsw_devlink_sb_occ_port_pool_get(struct devlink_port *devlink_port, 1404 unsigned int sb_index, u16 pool_index, 1405 u32 *p_cur, u32 *p_max) 1406{ 1407 struct mlxsw_core *mlxsw_core = devlink_priv(devlink_port->devlink); 1408 struct mlxsw_driver *mlxsw_driver = mlxsw_core->driver; 1409 struct mlxsw_core_port *mlxsw_core_port = __dl_port(devlink_port); 1410 1411 if (!mlxsw_driver->sb_occ_port_pool_get || 1412 !mlxsw_core_port_check(mlxsw_core_port)) 1413 return -EOPNOTSUPP; 1414 return mlxsw_driver->sb_occ_port_pool_get(mlxsw_core_port, sb_index, 1415 pool_index, p_cur, p_max); 1416} 1417 1418static int 1419mlxsw_devlink_sb_occ_tc_port_bind_get(struct devlink_port *devlink_port, 1420 unsigned int sb_index, u16 tc_index, 1421 enum devlink_sb_pool_type pool_type, 1422 u32 *p_cur, u32 *p_max) 1423{ 1424 struct mlxsw_core *mlxsw_core = devlink_priv(devlink_port->devlink); 1425 struct mlxsw_driver *mlxsw_driver = mlxsw_core->driver; 1426 struct mlxsw_core_port *mlxsw_core_port = __dl_port(devlink_port); 1427 1428 if (!mlxsw_driver->sb_occ_tc_port_bind_get || 1429 !mlxsw_core_port_check(mlxsw_core_port)) 1430 return -EOPNOTSUPP; 1431 return mlxsw_driver->sb_occ_tc_port_bind_get(mlxsw_core_port, 1432 sb_index, tc_index, 1433 pool_type, p_cur, p_max); 1434} 1435 1436static int 1437mlxsw_devlink_info_get(struct devlink *devlink, struct devlink_info_req *req, 1438 struct netlink_ext_ack *extack) 1439{ 1440 struct mlxsw_core *mlxsw_core = devlink_priv(devlink); 1441 char fw_info_psid[MLXSW_REG_MGIR_FW_INFO_PSID_SIZE]; 1442 u32 hw_rev, fw_major, fw_minor, fw_sub_minor; 1443 char mgir_pl[MLXSW_REG_MGIR_LEN]; 1444 char buf[32]; 1445 int err; 1446 1447 err = devlink_info_driver_name_put(req, 1448 mlxsw_core->bus_info->device_kind); 1449 if (err) 1450 return err; 1451 1452 mlxsw_reg_mgir_pack(mgir_pl); 1453 err = mlxsw_reg_query(mlxsw_core, MLXSW_REG(mgir), mgir_pl); 1454 if (err) 1455 return err; 1456 mlxsw_reg_mgir_unpack(mgir_pl, &hw_rev, fw_info_psid, &fw_major, 1457 &fw_minor, &fw_sub_minor); 1458 1459 sprintf(buf, "%X", hw_rev); 1460 err = devlink_info_version_fixed_put(req, "hw.revision", buf); 1461 if (err) 1462 return err; 1463 1464 err = devlink_info_version_fixed_put(req, 1465 DEVLINK_INFO_VERSION_GENERIC_FW_PSID, 1466 fw_info_psid); 1467 if (err) 1468 return err; 1469 1470 sprintf(buf, "%d.%d.%d", fw_major, fw_minor, fw_sub_minor); 1471 err = devlink_info_version_running_put(req, "fw.version", buf); 1472 if (err) 1473 return err; 1474 1475 return devlink_info_version_running_put(req, 1476 DEVLINK_INFO_VERSION_GENERIC_FW, 1477 buf); 1478} 1479 1480static int 1481mlxsw_devlink_core_bus_device_reload_down(struct devlink *devlink, 1482 bool netns_change, enum devlink_reload_action action, 1483 enum devlink_reload_limit limit, 1484 struct netlink_ext_ack *extack) 1485{ 1486 struct mlxsw_core *mlxsw_core = devlink_priv(devlink); 1487 1488 if (!(mlxsw_core->bus->features & MLXSW_BUS_F_RESET)) 1489 return -EOPNOTSUPP; 1490 1491 mlxsw_core_bus_device_unregister(mlxsw_core, true); 1492 return 0; 1493} 1494 1495static int 1496mlxsw_devlink_core_bus_device_reload_up(struct devlink *devlink, enum devlink_reload_action action, 1497 enum devlink_reload_limit limit, u32 *actions_performed, 1498 struct netlink_ext_ack *extack) 1499{ 1500 struct mlxsw_core *mlxsw_core = devlink_priv(devlink); 1501 1502 *actions_performed = BIT(DEVLINK_RELOAD_ACTION_DRIVER_REINIT) | 1503 BIT(DEVLINK_RELOAD_ACTION_FW_ACTIVATE); 1504 return mlxsw_core_bus_device_register(mlxsw_core->bus_info, 1505 mlxsw_core->bus, 1506 mlxsw_core->bus_priv, true, 1507 devlink, extack); 1508} 1509 1510static int mlxsw_devlink_flash_update(struct devlink *devlink, 1511 struct devlink_flash_update_params *params, 1512 struct netlink_ext_ack *extack) 1513{ 1514 struct mlxsw_core *mlxsw_core = devlink_priv(devlink); 1515 1516 return mlxsw_core_fw_flash_update(mlxsw_core, params, extack); 1517} 1518 1519static int mlxsw_devlink_trap_init(struct devlink *devlink, 1520 const struct devlink_trap *trap, 1521 void *trap_ctx) 1522{ 1523 struct mlxsw_core *mlxsw_core = devlink_priv(devlink); 1524 struct mlxsw_driver *mlxsw_driver = mlxsw_core->driver; 1525 1526 if (!mlxsw_driver->trap_init) 1527 return -EOPNOTSUPP; 1528 return mlxsw_driver->trap_init(mlxsw_core, trap, trap_ctx); 1529} 1530 1531static void mlxsw_devlink_trap_fini(struct devlink *devlink, 1532 const struct devlink_trap *trap, 1533 void *trap_ctx) 1534{ 1535 struct mlxsw_core *mlxsw_core = devlink_priv(devlink); 1536 struct mlxsw_driver *mlxsw_driver = mlxsw_core->driver; 1537 1538 if (!mlxsw_driver->trap_fini) 1539 return; 1540 mlxsw_driver->trap_fini(mlxsw_core, trap, trap_ctx); 1541} 1542 1543static int mlxsw_devlink_trap_action_set(struct devlink *devlink, 1544 const struct devlink_trap *trap, 1545 enum devlink_trap_action action, 1546 struct netlink_ext_ack *extack) 1547{ 1548 struct mlxsw_core *mlxsw_core = devlink_priv(devlink); 1549 struct mlxsw_driver *mlxsw_driver = mlxsw_core->driver; 1550 1551 if (!mlxsw_driver->trap_action_set) 1552 return -EOPNOTSUPP; 1553 return mlxsw_driver->trap_action_set(mlxsw_core, trap, action, extack); 1554} 1555 1556static int 1557mlxsw_devlink_trap_group_init(struct devlink *devlink, 1558 const struct devlink_trap_group *group) 1559{ 1560 struct mlxsw_core *mlxsw_core = devlink_priv(devlink); 1561 struct mlxsw_driver *mlxsw_driver = mlxsw_core->driver; 1562 1563 if (!mlxsw_driver->trap_group_init) 1564 return -EOPNOTSUPP; 1565 return mlxsw_driver->trap_group_init(mlxsw_core, group); 1566} 1567 1568static int 1569mlxsw_devlink_trap_group_set(struct devlink *devlink, 1570 const struct devlink_trap_group *group, 1571 const struct devlink_trap_policer *policer, 1572 struct netlink_ext_ack *extack) 1573{ 1574 struct mlxsw_core *mlxsw_core = devlink_priv(devlink); 1575 struct mlxsw_driver *mlxsw_driver = mlxsw_core->driver; 1576 1577 if (!mlxsw_driver->trap_group_set) 1578 return -EOPNOTSUPP; 1579 return mlxsw_driver->trap_group_set(mlxsw_core, group, policer, extack); 1580} 1581 1582static int 1583mlxsw_devlink_trap_policer_init(struct devlink *devlink, 1584 const struct devlink_trap_policer *policer) 1585{ 1586 struct mlxsw_core *mlxsw_core = devlink_priv(devlink); 1587 struct mlxsw_driver *mlxsw_driver = mlxsw_core->driver; 1588 1589 if (!mlxsw_driver->trap_policer_init) 1590 return -EOPNOTSUPP; 1591 return mlxsw_driver->trap_policer_init(mlxsw_core, policer); 1592} 1593 1594static void 1595mlxsw_devlink_trap_policer_fini(struct devlink *devlink, 1596 const struct devlink_trap_policer *policer) 1597{ 1598 struct mlxsw_core *mlxsw_core = devlink_priv(devlink); 1599 struct mlxsw_driver *mlxsw_driver = mlxsw_core->driver; 1600 1601 if (!mlxsw_driver->trap_policer_fini) 1602 return; 1603 mlxsw_driver->trap_policer_fini(mlxsw_core, policer); 1604} 1605 1606static int 1607mlxsw_devlink_trap_policer_set(struct devlink *devlink, 1608 const struct devlink_trap_policer *policer, 1609 u64 rate, u64 burst, 1610 struct netlink_ext_ack *extack) 1611{ 1612 struct mlxsw_core *mlxsw_core = devlink_priv(devlink); 1613 struct mlxsw_driver *mlxsw_driver = mlxsw_core->driver; 1614 1615 if (!mlxsw_driver->trap_policer_set) 1616 return -EOPNOTSUPP; 1617 return mlxsw_driver->trap_policer_set(mlxsw_core, policer, rate, burst, 1618 extack); 1619} 1620 1621static int 1622mlxsw_devlink_trap_policer_counter_get(struct devlink *devlink, 1623 const struct devlink_trap_policer *policer, 1624 u64 *p_drops) 1625{ 1626 struct mlxsw_core *mlxsw_core = devlink_priv(devlink); 1627 struct mlxsw_driver *mlxsw_driver = mlxsw_core->driver; 1628 1629 if (!mlxsw_driver->trap_policer_counter_get) 1630 return -EOPNOTSUPP; 1631 return mlxsw_driver->trap_policer_counter_get(mlxsw_core, policer, 1632 p_drops); 1633} 1634 1635static const struct devlink_ops mlxsw_devlink_ops = { 1636 .reload_actions = BIT(DEVLINK_RELOAD_ACTION_DRIVER_REINIT) | 1637 BIT(DEVLINK_RELOAD_ACTION_FW_ACTIVATE), 1638 .reload_down = mlxsw_devlink_core_bus_device_reload_down, 1639 .reload_up = mlxsw_devlink_core_bus_device_reload_up, 1640 .port_type_set = mlxsw_devlink_port_type_set, 1641 .port_split = mlxsw_devlink_port_split, 1642 .port_unsplit = mlxsw_devlink_port_unsplit, 1643 .sb_pool_get = mlxsw_devlink_sb_pool_get, 1644 .sb_pool_set = mlxsw_devlink_sb_pool_set, 1645 .sb_port_pool_get = mlxsw_devlink_sb_port_pool_get, 1646 .sb_port_pool_set = mlxsw_devlink_sb_port_pool_set, 1647 .sb_tc_pool_bind_get = mlxsw_devlink_sb_tc_pool_bind_get, 1648 .sb_tc_pool_bind_set = mlxsw_devlink_sb_tc_pool_bind_set, 1649 .sb_occ_snapshot = mlxsw_devlink_sb_occ_snapshot, 1650 .sb_occ_max_clear = mlxsw_devlink_sb_occ_max_clear, 1651 .sb_occ_port_pool_get = mlxsw_devlink_sb_occ_port_pool_get, 1652 .sb_occ_tc_port_bind_get = mlxsw_devlink_sb_occ_tc_port_bind_get, 1653 .info_get = mlxsw_devlink_info_get, 1654 .flash_update = mlxsw_devlink_flash_update, 1655 .trap_init = mlxsw_devlink_trap_init, 1656 .trap_fini = mlxsw_devlink_trap_fini, 1657 .trap_action_set = mlxsw_devlink_trap_action_set, 1658 .trap_group_init = mlxsw_devlink_trap_group_init, 1659 .trap_group_set = mlxsw_devlink_trap_group_set, 1660 .trap_policer_init = mlxsw_devlink_trap_policer_init, 1661 .trap_policer_fini = mlxsw_devlink_trap_policer_fini, 1662 .trap_policer_set = mlxsw_devlink_trap_policer_set, 1663 .trap_policer_counter_get = mlxsw_devlink_trap_policer_counter_get, 1664}; 1665 1666static int mlxsw_core_params_register(struct mlxsw_core *mlxsw_core) 1667{ 1668 int err; 1669 1670 err = mlxsw_core_fw_params_register(mlxsw_core); 1671 if (err) 1672 return err; 1673 1674 if (mlxsw_core->driver->params_register) { 1675 err = mlxsw_core->driver->params_register(mlxsw_core); 1676 if (err) 1677 goto err_params_register; 1678 } 1679 return 0; 1680 1681err_params_register: 1682 mlxsw_core_fw_params_unregister(mlxsw_core); 1683 return err; 1684} 1685 1686static void mlxsw_core_params_unregister(struct mlxsw_core *mlxsw_core) 1687{ 1688 mlxsw_core_fw_params_unregister(mlxsw_core); 1689 if (mlxsw_core->driver->params_register) 1690 mlxsw_core->driver->params_unregister(mlxsw_core); 1691} 1692 1693struct mlxsw_core_health_event { 1694 struct mlxsw_core *mlxsw_core; 1695 char mfde_pl[MLXSW_REG_MFDE_LEN]; 1696 struct work_struct work; 1697}; 1698 1699static void mlxsw_core_health_event_work(struct work_struct *work) 1700{ 1701 struct mlxsw_core_health_event *event; 1702 struct mlxsw_core *mlxsw_core; 1703 1704 event = container_of(work, struct mlxsw_core_health_event, work); 1705 mlxsw_core = event->mlxsw_core; 1706 devlink_health_report(mlxsw_core->health.fw_fatal, "FW fatal event occurred", 1707 event->mfde_pl); 1708 kfree(event); 1709} 1710 1711static void mlxsw_core_health_listener_func(const struct mlxsw_reg_info *reg, 1712 char *mfde_pl, void *priv) 1713{ 1714 struct mlxsw_core_health_event *event; 1715 struct mlxsw_core *mlxsw_core = priv; 1716 1717 event = kmalloc(sizeof(*event), GFP_ATOMIC); 1718 if (!event) 1719 return; 1720 event->mlxsw_core = mlxsw_core; 1721 memcpy(event->mfde_pl, mfde_pl, sizeof(event->mfde_pl)); 1722 INIT_WORK(&event->work, mlxsw_core_health_event_work); 1723 mlxsw_core_schedule_work(&event->work); 1724} 1725 1726static const struct mlxsw_listener mlxsw_core_health_listener = 1727 MLXSW_CORE_EVENTL(mlxsw_core_health_listener_func, MFDE); 1728 1729static int 1730mlxsw_core_health_fw_fatal_dump_fatal_cause(const char *mfde_pl, 1731 struct devlink_fmsg *fmsg) 1732{ 1733 u32 val, tile_v; 1734 int err; 1735 1736 val = mlxsw_reg_mfde_fatal_cause_id_get(mfde_pl); 1737 err = devlink_fmsg_u32_pair_put(fmsg, "cause_id", val); 1738 if (err) 1739 return err; 1740 tile_v = mlxsw_reg_mfde_fatal_cause_tile_v_get(mfde_pl); 1741 if (tile_v) { 1742 val = mlxsw_reg_mfde_fatal_cause_tile_index_get(mfde_pl); 1743 err = devlink_fmsg_u8_pair_put(fmsg, "tile_index", val); 1744 if (err) 1745 return err; 1746 } 1747 1748 return 0; 1749} 1750 1751static int 1752mlxsw_core_health_fw_fatal_dump_fw_assert(const char *mfde_pl, 1753 struct devlink_fmsg *fmsg) 1754{ 1755 u32 val, tile_v; 1756 int err; 1757 1758 val = mlxsw_reg_mfde_fw_assert_var0_get(mfde_pl); 1759 err = devlink_fmsg_u32_pair_put(fmsg, "var0", val); 1760 if (err) 1761 return err; 1762 val = mlxsw_reg_mfde_fw_assert_var1_get(mfde_pl); 1763 err = devlink_fmsg_u32_pair_put(fmsg, "var1", val); 1764 if (err) 1765 return err; 1766 val = mlxsw_reg_mfde_fw_assert_var2_get(mfde_pl); 1767 err = devlink_fmsg_u32_pair_put(fmsg, "var2", val); 1768 if (err) 1769 return err; 1770 val = mlxsw_reg_mfde_fw_assert_var3_get(mfde_pl); 1771 err = devlink_fmsg_u32_pair_put(fmsg, "var3", val); 1772 if (err) 1773 return err; 1774 val = mlxsw_reg_mfde_fw_assert_var4_get(mfde_pl); 1775 err = devlink_fmsg_u32_pair_put(fmsg, "var4", val); 1776 if (err) 1777 return err; 1778 val = mlxsw_reg_mfde_fw_assert_existptr_get(mfde_pl); 1779 err = devlink_fmsg_u32_pair_put(fmsg, "existptr", val); 1780 if (err) 1781 return err; 1782 val = mlxsw_reg_mfde_fw_assert_callra_get(mfde_pl); 1783 err = devlink_fmsg_u32_pair_put(fmsg, "callra", val); 1784 if (err) 1785 return err; 1786 val = mlxsw_reg_mfde_fw_assert_oe_get(mfde_pl); 1787 err = devlink_fmsg_bool_pair_put(fmsg, "old_event", val); 1788 if (err) 1789 return err; 1790 tile_v = mlxsw_reg_mfde_fw_assert_tile_v_get(mfde_pl); 1791 if (tile_v) { 1792 val = mlxsw_reg_mfde_fw_assert_tile_index_get(mfde_pl); 1793 err = devlink_fmsg_u8_pair_put(fmsg, "tile_index", val); 1794 if (err) 1795 return err; 1796 } 1797 val = mlxsw_reg_mfde_fw_assert_ext_synd_get(mfde_pl); 1798 err = devlink_fmsg_u32_pair_put(fmsg, "ext_synd", val); 1799 if (err) 1800 return err; 1801 1802 return 0; 1803} 1804 1805static int 1806mlxsw_core_health_fw_fatal_dump_kvd_im_stop(const char *mfde_pl, 1807 struct devlink_fmsg *fmsg) 1808{ 1809 u32 val; 1810 int err; 1811 1812 val = mlxsw_reg_mfde_kvd_im_stop_oe_get(mfde_pl); 1813 err = devlink_fmsg_bool_pair_put(fmsg, "old_event", val); 1814 if (err) 1815 return err; 1816 val = mlxsw_reg_mfde_kvd_im_stop_pipes_mask_get(mfde_pl); 1817 return devlink_fmsg_u32_pair_put(fmsg, "pipes_mask", val); 1818} 1819 1820static int 1821mlxsw_core_health_fw_fatal_dump_crspace_to(const char *mfde_pl, 1822 struct devlink_fmsg *fmsg) 1823{ 1824 u32 val; 1825 int err; 1826 1827 val = mlxsw_reg_mfde_crspace_to_log_address_get(mfde_pl); 1828 err = devlink_fmsg_u32_pair_put(fmsg, "log_address", val); 1829 if (err) 1830 return err; 1831 val = mlxsw_reg_mfde_crspace_to_oe_get(mfde_pl); 1832 err = devlink_fmsg_bool_pair_put(fmsg, "old_event", val); 1833 if (err) 1834 return err; 1835 val = mlxsw_reg_mfde_crspace_to_log_id_get(mfde_pl); 1836 err = devlink_fmsg_u8_pair_put(fmsg, "log_irisc_id", val); 1837 if (err) 1838 return err; 1839 val = mlxsw_reg_mfde_crspace_to_log_ip_get(mfde_pl); 1840 err = devlink_fmsg_u64_pair_put(fmsg, "log_ip", val); 1841 if (err) 1842 return err; 1843 1844 return 0; 1845} 1846 1847static int mlxsw_core_health_fw_fatal_dump(struct devlink_health_reporter *reporter, 1848 struct devlink_fmsg *fmsg, void *priv_ctx, 1849 struct netlink_ext_ack *extack) 1850{ 1851 char *mfde_pl = priv_ctx; 1852 char *val_str; 1853 u8 event_id; 1854 u32 val; 1855 int err; 1856 1857 if (!priv_ctx) 1858 /* User-triggered dumps are not possible */ 1859 return -EOPNOTSUPP; 1860 1861 val = mlxsw_reg_mfde_irisc_id_get(mfde_pl); 1862 err = devlink_fmsg_u8_pair_put(fmsg, "irisc_id", val); 1863 if (err) 1864 return err; 1865 err = devlink_fmsg_arr_pair_nest_start(fmsg, "event"); 1866 if (err) 1867 return err; 1868 1869 event_id = mlxsw_reg_mfde_event_id_get(mfde_pl); 1870 err = devlink_fmsg_u32_pair_put(fmsg, "id", event_id); 1871 if (err) 1872 return err; 1873 switch (event_id) { 1874 case MLXSW_REG_MFDE_EVENT_ID_CRSPACE_TO: 1875 val_str = "CR space timeout"; 1876 break; 1877 case MLXSW_REG_MFDE_EVENT_ID_KVD_IM_STOP: 1878 val_str = "KVD insertion machine stopped"; 1879 break; 1880 case MLXSW_REG_MFDE_EVENT_ID_TEST: 1881 val_str = "Test"; 1882 break; 1883 case MLXSW_REG_MFDE_EVENT_ID_FW_ASSERT: 1884 val_str = "FW assert"; 1885 break; 1886 case MLXSW_REG_MFDE_EVENT_ID_FATAL_CAUSE: 1887 val_str = "Fatal cause"; 1888 break; 1889 default: 1890 val_str = NULL; 1891 } 1892 if (val_str) { 1893 err = devlink_fmsg_string_pair_put(fmsg, "desc", val_str); 1894 if (err) 1895 return err; 1896 } 1897 1898 err = devlink_fmsg_arr_pair_nest_end(fmsg); 1899 if (err) 1900 return err; 1901 1902 err = devlink_fmsg_arr_pair_nest_start(fmsg, "severity"); 1903 if (err) 1904 return err; 1905 1906 val = mlxsw_reg_mfde_severity_get(mfde_pl); 1907 err = devlink_fmsg_u8_pair_put(fmsg, "id", val); 1908 if (err) 1909 return err; 1910 switch (val) { 1911 case MLXSW_REG_MFDE_SEVERITY_FATL: 1912 val_str = "Fatal"; 1913 break; 1914 case MLXSW_REG_MFDE_SEVERITY_NRML: 1915 val_str = "Normal"; 1916 break; 1917 case MLXSW_REG_MFDE_SEVERITY_INTR: 1918 val_str = "Debug"; 1919 break; 1920 default: 1921 val_str = NULL; 1922 } 1923 if (val_str) { 1924 err = devlink_fmsg_string_pair_put(fmsg, "desc", val_str); 1925 if (err) 1926 return err; 1927 } 1928 1929 err = devlink_fmsg_arr_pair_nest_end(fmsg); 1930 if (err) 1931 return err; 1932 1933 val = mlxsw_reg_mfde_method_get(mfde_pl); 1934 switch (val) { 1935 case MLXSW_REG_MFDE_METHOD_QUERY: 1936 val_str = "query"; 1937 break; 1938 case MLXSW_REG_MFDE_METHOD_WRITE: 1939 val_str = "write"; 1940 break; 1941 default: 1942 val_str = NULL; 1943 } 1944 if (val_str) { 1945 err = devlink_fmsg_string_pair_put(fmsg, "method", val_str); 1946 if (err) 1947 return err; 1948 } 1949 1950 val = mlxsw_reg_mfde_long_process_get(mfde_pl); 1951 err = devlink_fmsg_bool_pair_put(fmsg, "long_process", val); 1952 if (err) 1953 return err; 1954 1955 val = mlxsw_reg_mfde_command_type_get(mfde_pl); 1956 switch (val) { 1957 case MLXSW_REG_MFDE_COMMAND_TYPE_MAD: 1958 val_str = "mad"; 1959 break; 1960 case MLXSW_REG_MFDE_COMMAND_TYPE_EMAD: 1961 val_str = "emad"; 1962 break; 1963 case MLXSW_REG_MFDE_COMMAND_TYPE_CMDIF: 1964 val_str = "cmdif"; 1965 break; 1966 default: 1967 val_str = NULL; 1968 } 1969 if (val_str) { 1970 err = devlink_fmsg_string_pair_put(fmsg, "command_type", val_str); 1971 if (err) 1972 return err; 1973 } 1974 1975 val = mlxsw_reg_mfde_reg_attr_id_get(mfde_pl); 1976 err = devlink_fmsg_u32_pair_put(fmsg, "reg_attr_id", val); 1977 if (err) 1978 return err; 1979 1980 switch (event_id) { 1981 case MLXSW_REG_MFDE_EVENT_ID_CRSPACE_TO: 1982 return mlxsw_core_health_fw_fatal_dump_crspace_to(mfde_pl, 1983 fmsg); 1984 case MLXSW_REG_MFDE_EVENT_ID_KVD_IM_STOP: 1985 return mlxsw_core_health_fw_fatal_dump_kvd_im_stop(mfde_pl, 1986 fmsg); 1987 case MLXSW_REG_MFDE_EVENT_ID_FW_ASSERT: 1988 return mlxsw_core_health_fw_fatal_dump_fw_assert(mfde_pl, fmsg); 1989 case MLXSW_REG_MFDE_EVENT_ID_FATAL_CAUSE: 1990 return mlxsw_core_health_fw_fatal_dump_fatal_cause(mfde_pl, 1991 fmsg); 1992 } 1993 1994 return 0; 1995} 1996 1997static int 1998mlxsw_core_health_fw_fatal_test(struct devlink_health_reporter *reporter, 1999 struct netlink_ext_ack *extack) 2000{ 2001 struct mlxsw_core *mlxsw_core = devlink_health_reporter_priv(reporter); 2002 char mfgd_pl[MLXSW_REG_MFGD_LEN]; 2003 int err; 2004 2005 /* Read the register first to make sure no other bits are changed. */ 2006 err = mlxsw_reg_query(mlxsw_core, MLXSW_REG(mfgd), mfgd_pl); 2007 if (err) 2008 return err; 2009 mlxsw_reg_mfgd_trigger_test_set(mfgd_pl, true); 2010 return mlxsw_reg_write(mlxsw_core, MLXSW_REG(mfgd), mfgd_pl); 2011} 2012 2013static const struct devlink_health_reporter_ops 2014mlxsw_core_health_fw_fatal_ops = { 2015 .name = "fw_fatal", 2016 .dump = mlxsw_core_health_fw_fatal_dump, 2017 .test = mlxsw_core_health_fw_fatal_test, 2018}; 2019 2020static int mlxsw_core_health_fw_fatal_config(struct mlxsw_core *mlxsw_core, 2021 bool enable) 2022{ 2023 char mfgd_pl[MLXSW_REG_MFGD_LEN]; 2024 int err; 2025 2026 /* Read the register first to make sure no other bits are changed. */ 2027 err = mlxsw_reg_query(mlxsw_core, MLXSW_REG(mfgd), mfgd_pl); 2028 if (err) 2029 return err; 2030 mlxsw_reg_mfgd_fatal_event_mode_set(mfgd_pl, enable); 2031 return mlxsw_reg_write(mlxsw_core, MLXSW_REG(mfgd), mfgd_pl); 2032} 2033 2034static int mlxsw_core_health_init(struct mlxsw_core *mlxsw_core) 2035{ 2036 struct devlink *devlink = priv_to_devlink(mlxsw_core); 2037 struct devlink_health_reporter *fw_fatal; 2038 int err; 2039 2040 if (!(mlxsw_core->bus->features & MLXSW_BUS_F_TXRX)) 2041 return 0; 2042 2043 fw_fatal = devlink_health_reporter_create(devlink, &mlxsw_core_health_fw_fatal_ops, 2044 0, mlxsw_core); 2045 if (IS_ERR(fw_fatal)) { 2046 dev_err(mlxsw_core->bus_info->dev, "Failed to create fw fatal reporter"); 2047 return PTR_ERR(fw_fatal); 2048 } 2049 mlxsw_core->health.fw_fatal = fw_fatal; 2050 2051 err = mlxsw_core_trap_register(mlxsw_core, &mlxsw_core_health_listener, mlxsw_core); 2052 if (err) 2053 goto err_trap_register; 2054 2055 err = mlxsw_core_health_fw_fatal_config(mlxsw_core, true); 2056 if (err) 2057 goto err_fw_fatal_config; 2058 2059 return 0; 2060 2061err_fw_fatal_config: 2062 mlxsw_core_trap_unregister(mlxsw_core, &mlxsw_core_health_listener, mlxsw_core); 2063err_trap_register: 2064 devlink_health_reporter_destroy(mlxsw_core->health.fw_fatal); 2065 return err; 2066} 2067 2068static void mlxsw_core_health_fini(struct mlxsw_core *mlxsw_core) 2069{ 2070 if (!(mlxsw_core->bus->features & MLXSW_BUS_F_TXRX)) 2071 return; 2072 2073 mlxsw_core_health_fw_fatal_config(mlxsw_core, false); 2074 mlxsw_core_trap_unregister(mlxsw_core, &mlxsw_core_health_listener, mlxsw_core); 2075 /* Make sure there is no more event work scheduled */ 2076 mlxsw_core_flush_owq(); 2077 devlink_health_reporter_destroy(mlxsw_core->health.fw_fatal); 2078} 2079 2080static int 2081__mlxsw_core_bus_device_register(const struct mlxsw_bus_info *mlxsw_bus_info, 2082 const struct mlxsw_bus *mlxsw_bus, 2083 void *bus_priv, bool reload, 2084 struct devlink *devlink, 2085 struct netlink_ext_ack *extack) 2086{ 2087 const char *device_kind = mlxsw_bus_info->device_kind; 2088 struct mlxsw_core *mlxsw_core; 2089 struct mlxsw_driver *mlxsw_driver; 2090 size_t alloc_size; 2091 int err; 2092 2093 mlxsw_driver = mlxsw_core_driver_get(device_kind); 2094 if (!mlxsw_driver) 2095 return -EINVAL; 2096 2097 if (!reload) { 2098 alloc_size = sizeof(*mlxsw_core) + mlxsw_driver->priv_size; 2099 devlink = devlink_alloc(&mlxsw_devlink_ops, alloc_size, 2100 mlxsw_bus_info->dev); 2101 if (!devlink) { 2102 err = -ENOMEM; 2103 goto err_devlink_alloc; 2104 } 2105 } 2106 2107 mlxsw_core = devlink_priv(devlink); 2108 INIT_LIST_HEAD(&mlxsw_core->rx_listener_list); 2109 INIT_LIST_HEAD(&mlxsw_core->event_listener_list); 2110 mlxsw_core->driver = mlxsw_driver; 2111 mlxsw_core->bus = mlxsw_bus; 2112 mlxsw_core->bus_priv = bus_priv; 2113 mlxsw_core->bus_info = mlxsw_bus_info; 2114 2115 err = mlxsw_bus->init(bus_priv, mlxsw_core, mlxsw_driver->profile, 2116 &mlxsw_core->res); 2117 if (err) 2118 goto err_bus_init; 2119 2120 if (mlxsw_driver->resources_register && !reload) { 2121 err = mlxsw_driver->resources_register(mlxsw_core); 2122 if (err) 2123 goto err_register_resources; 2124 } 2125 2126 err = mlxsw_ports_init(mlxsw_core, reload); 2127 if (err) 2128 goto err_ports_init; 2129 2130 if (MLXSW_CORE_RES_VALID(mlxsw_core, MAX_LAG) && 2131 MLXSW_CORE_RES_VALID(mlxsw_core, MAX_LAG_MEMBERS)) { 2132 alloc_size = sizeof(*mlxsw_core->lag.mapping) * 2133 MLXSW_CORE_RES_GET(mlxsw_core, MAX_LAG) * 2134 MLXSW_CORE_RES_GET(mlxsw_core, MAX_LAG_MEMBERS); 2135 mlxsw_core->lag.mapping = kzalloc(alloc_size, GFP_KERNEL); 2136 if (!mlxsw_core->lag.mapping) { 2137 err = -ENOMEM; 2138 goto err_alloc_lag_mapping; 2139 } 2140 } 2141 2142 err = mlxsw_core_trap_groups_set(mlxsw_core); 2143 if (err) 2144 goto err_trap_groups_set; 2145 2146 err = mlxsw_emad_init(mlxsw_core); 2147 if (err) 2148 goto err_emad_init; 2149 2150 if (!reload) { 2151 err = mlxsw_core_params_register(mlxsw_core); 2152 if (err) 2153 goto err_register_params; 2154 } 2155 2156 err = mlxsw_core_fw_rev_validate(mlxsw_core, mlxsw_bus_info, mlxsw_driver->fw_req_rev, 2157 mlxsw_driver->fw_filename); 2158 if (err) 2159 goto err_fw_rev_validate; 2160 2161 err = mlxsw_linecards_init(mlxsw_core, mlxsw_bus_info); 2162 if (err) 2163 goto err_linecards_init; 2164 2165 err = mlxsw_core_health_init(mlxsw_core); 2166 if (err) 2167 goto err_health_init; 2168 2169 err = mlxsw_hwmon_init(mlxsw_core, mlxsw_bus_info, &mlxsw_core->hwmon); 2170 if (err) 2171 goto err_hwmon_init; 2172 2173 err = mlxsw_thermal_init(mlxsw_core, mlxsw_bus_info, 2174 &mlxsw_core->thermal); 2175 if (err) 2176 goto err_thermal_init; 2177 2178 err = mlxsw_env_init(mlxsw_core, mlxsw_bus_info, &mlxsw_core->env); 2179 if (err) 2180 goto err_env_init; 2181 2182 if (mlxsw_driver->init) { 2183 err = mlxsw_driver->init(mlxsw_core, mlxsw_bus_info, extack); 2184 if (err) 2185 goto err_driver_init; 2186 } 2187 2188 if (!reload) { 2189 devlink_set_features(devlink, DEVLINK_F_RELOAD); 2190 devlink_register(devlink); 2191 } 2192 return 0; 2193 2194err_driver_init: 2195 mlxsw_env_fini(mlxsw_core->env); 2196err_env_init: 2197 mlxsw_thermal_fini(mlxsw_core->thermal); 2198err_thermal_init: 2199 mlxsw_hwmon_fini(mlxsw_core->hwmon); 2200err_hwmon_init: 2201 mlxsw_core_health_fini(mlxsw_core); 2202err_health_init: 2203 mlxsw_linecards_fini(mlxsw_core); 2204err_linecards_init: 2205err_fw_rev_validate: 2206 if (!reload) 2207 mlxsw_core_params_unregister(mlxsw_core); 2208err_register_params: 2209 mlxsw_emad_fini(mlxsw_core); 2210err_emad_init: 2211err_trap_groups_set: 2212 kfree(mlxsw_core->lag.mapping); 2213err_alloc_lag_mapping: 2214 mlxsw_ports_fini(mlxsw_core, reload); 2215err_ports_init: 2216 if (!reload) 2217 devlink_resources_unregister(devlink); 2218err_register_resources: 2219 mlxsw_bus->fini(bus_priv); 2220err_bus_init: 2221 if (!reload) 2222 devlink_free(devlink); 2223err_devlink_alloc: 2224 return err; 2225} 2226 2227int mlxsw_core_bus_device_register(const struct mlxsw_bus_info *mlxsw_bus_info, 2228 const struct mlxsw_bus *mlxsw_bus, 2229 void *bus_priv, bool reload, 2230 struct devlink *devlink, 2231 struct netlink_ext_ack *extack) 2232{ 2233 bool called_again = false; 2234 int err; 2235 2236again: 2237 err = __mlxsw_core_bus_device_register(mlxsw_bus_info, mlxsw_bus, 2238 bus_priv, reload, 2239 devlink, extack); 2240 /* -EAGAIN is returned in case the FW was updated. FW needs 2241 * a reset, so lets try to call __mlxsw_core_bus_device_register() 2242 * again. 2243 */ 2244 if (err == -EAGAIN && !called_again) { 2245 called_again = true; 2246 goto again; 2247 } 2248 2249 return err; 2250} 2251EXPORT_SYMBOL(mlxsw_core_bus_device_register); 2252 2253void mlxsw_core_bus_device_unregister(struct mlxsw_core *mlxsw_core, 2254 bool reload) 2255{ 2256 struct devlink *devlink = priv_to_devlink(mlxsw_core); 2257 2258 if (!reload) 2259 devlink_unregister(devlink); 2260 2261 if (devlink_is_reload_failed(devlink)) { 2262 if (!reload) 2263 /* Only the parts that were not de-initialized in the 2264 * failed reload attempt need to be de-initialized. 2265 */ 2266 goto reload_fail_deinit; 2267 else 2268 return; 2269 } 2270 2271 if (mlxsw_core->driver->fini) 2272 mlxsw_core->driver->fini(mlxsw_core); 2273 mlxsw_env_fini(mlxsw_core->env); 2274 mlxsw_thermal_fini(mlxsw_core->thermal); 2275 mlxsw_hwmon_fini(mlxsw_core->hwmon); 2276 mlxsw_core_health_fini(mlxsw_core); 2277 mlxsw_linecards_fini(mlxsw_core); 2278 if (!reload) 2279 mlxsw_core_params_unregister(mlxsw_core); 2280 mlxsw_emad_fini(mlxsw_core); 2281 kfree(mlxsw_core->lag.mapping); 2282 mlxsw_ports_fini(mlxsw_core, reload); 2283 if (!reload) 2284 devlink_resources_unregister(devlink); 2285 mlxsw_core->bus->fini(mlxsw_core->bus_priv); 2286 if (!reload) 2287 devlink_free(devlink); 2288 2289 return; 2290 2291reload_fail_deinit: 2292 mlxsw_core_params_unregister(mlxsw_core); 2293 devlink_resources_unregister(devlink); 2294 devlink_free(devlink); 2295} 2296EXPORT_SYMBOL(mlxsw_core_bus_device_unregister); 2297 2298bool mlxsw_core_skb_transmit_busy(struct mlxsw_core *mlxsw_core, 2299 const struct mlxsw_tx_info *tx_info) 2300{ 2301 return mlxsw_core->bus->skb_transmit_busy(mlxsw_core->bus_priv, 2302 tx_info); 2303} 2304EXPORT_SYMBOL(mlxsw_core_skb_transmit_busy); 2305 2306int mlxsw_core_skb_transmit(struct mlxsw_core *mlxsw_core, struct sk_buff *skb, 2307 const struct mlxsw_tx_info *tx_info) 2308{ 2309 return mlxsw_core->bus->skb_transmit(mlxsw_core->bus_priv, skb, 2310 tx_info); 2311} 2312EXPORT_SYMBOL(mlxsw_core_skb_transmit); 2313 2314void mlxsw_core_ptp_transmitted(struct mlxsw_core *mlxsw_core, 2315 struct sk_buff *skb, u16 local_port) 2316{ 2317 if (mlxsw_core->driver->ptp_transmitted) 2318 mlxsw_core->driver->ptp_transmitted(mlxsw_core, skb, 2319 local_port); 2320} 2321EXPORT_SYMBOL(mlxsw_core_ptp_transmitted); 2322 2323static bool __is_rx_listener_equal(const struct mlxsw_rx_listener *rxl_a, 2324 const struct mlxsw_rx_listener *rxl_b) 2325{ 2326 return (rxl_a->func == rxl_b->func && 2327 rxl_a->local_port == rxl_b->local_port && 2328 rxl_a->trap_id == rxl_b->trap_id && 2329 rxl_a->mirror_reason == rxl_b->mirror_reason); 2330} 2331 2332static struct mlxsw_rx_listener_item * 2333__find_rx_listener_item(struct mlxsw_core *mlxsw_core, 2334 const struct mlxsw_rx_listener *rxl) 2335{ 2336 struct mlxsw_rx_listener_item *rxl_item; 2337 2338 list_for_each_entry(rxl_item, &mlxsw_core->rx_listener_list, list) { 2339 if (__is_rx_listener_equal(&rxl_item->rxl, rxl)) 2340 return rxl_item; 2341 } 2342 return NULL; 2343} 2344 2345int mlxsw_core_rx_listener_register(struct mlxsw_core *mlxsw_core, 2346 const struct mlxsw_rx_listener *rxl, 2347 void *priv, bool enabled) 2348{ 2349 struct mlxsw_rx_listener_item *rxl_item; 2350 2351 rxl_item = __find_rx_listener_item(mlxsw_core, rxl); 2352 if (rxl_item) 2353 return -EEXIST; 2354 rxl_item = kmalloc(sizeof(*rxl_item), GFP_KERNEL); 2355 if (!rxl_item) 2356 return -ENOMEM; 2357 rxl_item->rxl = *rxl; 2358 rxl_item->priv = priv; 2359 rxl_item->enabled = enabled; 2360 2361 list_add_rcu(&rxl_item->list, &mlxsw_core->rx_listener_list); 2362 return 0; 2363} 2364EXPORT_SYMBOL(mlxsw_core_rx_listener_register); 2365 2366void mlxsw_core_rx_listener_unregister(struct mlxsw_core *mlxsw_core, 2367 const struct mlxsw_rx_listener *rxl) 2368{ 2369 struct mlxsw_rx_listener_item *rxl_item; 2370 2371 rxl_item = __find_rx_listener_item(mlxsw_core, rxl); 2372 if (!rxl_item) 2373 return; 2374 list_del_rcu(&rxl_item->list); 2375 synchronize_rcu(); 2376 kfree(rxl_item); 2377} 2378EXPORT_SYMBOL(mlxsw_core_rx_listener_unregister); 2379 2380static void 2381mlxsw_core_rx_listener_state_set(struct mlxsw_core *mlxsw_core, 2382 const struct mlxsw_rx_listener *rxl, 2383 bool enabled) 2384{ 2385 struct mlxsw_rx_listener_item *rxl_item; 2386 2387 rxl_item = __find_rx_listener_item(mlxsw_core, rxl); 2388 if (WARN_ON(!rxl_item)) 2389 return; 2390 rxl_item->enabled = enabled; 2391} 2392 2393static void mlxsw_core_event_listener_func(struct sk_buff *skb, u16 local_port, 2394 void *priv) 2395{ 2396 struct mlxsw_event_listener_item *event_listener_item = priv; 2397 struct mlxsw_core *mlxsw_core; 2398 struct mlxsw_reg_info reg; 2399 char *payload; 2400 char *reg_tlv; 2401 char *op_tlv; 2402 2403 mlxsw_core = event_listener_item->mlxsw_core; 2404 trace_devlink_hwmsg(priv_to_devlink(mlxsw_core), true, 0, 2405 skb->data, skb->len); 2406 2407 mlxsw_emad_tlv_parse(skb); 2408 op_tlv = mlxsw_emad_op_tlv(skb); 2409 reg_tlv = mlxsw_emad_reg_tlv(skb); 2410 2411 reg.id = mlxsw_emad_op_tlv_register_id_get(op_tlv); 2412 reg.len = (mlxsw_emad_reg_tlv_len_get(reg_tlv) - 1) * sizeof(u32); 2413 payload = mlxsw_emad_reg_payload(reg_tlv); 2414 event_listener_item->el.func(®, payload, event_listener_item->priv); 2415 dev_kfree_skb(skb); 2416} 2417 2418static bool __is_event_listener_equal(const struct mlxsw_event_listener *el_a, 2419 const struct mlxsw_event_listener *el_b) 2420{ 2421 return (el_a->func == el_b->func && 2422 el_a->trap_id == el_b->trap_id); 2423} 2424 2425static struct mlxsw_event_listener_item * 2426__find_event_listener_item(struct mlxsw_core *mlxsw_core, 2427 const struct mlxsw_event_listener *el) 2428{ 2429 struct mlxsw_event_listener_item *el_item; 2430 2431 list_for_each_entry(el_item, &mlxsw_core->event_listener_list, list) { 2432 if (__is_event_listener_equal(&el_item->el, el)) 2433 return el_item; 2434 } 2435 return NULL; 2436} 2437 2438int mlxsw_core_event_listener_register(struct mlxsw_core *mlxsw_core, 2439 const struct mlxsw_event_listener *el, 2440 void *priv) 2441{ 2442 int err; 2443 struct mlxsw_event_listener_item *el_item; 2444 const struct mlxsw_rx_listener rxl = { 2445 .func = mlxsw_core_event_listener_func, 2446 .local_port = MLXSW_PORT_DONT_CARE, 2447 .trap_id = el->trap_id, 2448 }; 2449 2450 el_item = __find_event_listener_item(mlxsw_core, el); 2451 if (el_item) 2452 return -EEXIST; 2453 el_item = kmalloc(sizeof(*el_item), GFP_KERNEL); 2454 if (!el_item) 2455 return -ENOMEM; 2456 el_item->mlxsw_core = mlxsw_core; 2457 el_item->el = *el; 2458 el_item->priv = priv; 2459 2460 err = mlxsw_core_rx_listener_register(mlxsw_core, &rxl, el_item, true); 2461 if (err) 2462 goto err_rx_listener_register; 2463 2464 /* No reason to save item if we did not manage to register an RX 2465 * listener for it. 2466 */ 2467 list_add_rcu(&el_item->list, &mlxsw_core->event_listener_list); 2468 2469 return 0; 2470 2471err_rx_listener_register: 2472 kfree(el_item); 2473 return err; 2474} 2475EXPORT_SYMBOL(mlxsw_core_event_listener_register); 2476 2477void mlxsw_core_event_listener_unregister(struct mlxsw_core *mlxsw_core, 2478 const struct mlxsw_event_listener *el) 2479{ 2480 struct mlxsw_event_listener_item *el_item; 2481 const struct mlxsw_rx_listener rxl = { 2482 .func = mlxsw_core_event_listener_func, 2483 .local_port = MLXSW_PORT_DONT_CARE, 2484 .trap_id = el->trap_id, 2485 }; 2486 2487 el_item = __find_event_listener_item(mlxsw_core, el); 2488 if (!el_item) 2489 return; 2490 mlxsw_core_rx_listener_unregister(mlxsw_core, &rxl); 2491 list_del(&el_item->list); 2492 kfree(el_item); 2493} 2494EXPORT_SYMBOL(mlxsw_core_event_listener_unregister); 2495 2496static int mlxsw_core_listener_register(struct mlxsw_core *mlxsw_core, 2497 const struct mlxsw_listener *listener, 2498 void *priv, bool enabled) 2499{ 2500 if (listener->is_event) { 2501 WARN_ON(!enabled); 2502 return mlxsw_core_event_listener_register(mlxsw_core, 2503 &listener->event_listener, 2504 priv); 2505 } else { 2506 return mlxsw_core_rx_listener_register(mlxsw_core, 2507 &listener->rx_listener, 2508 priv, enabled); 2509 } 2510} 2511 2512static void mlxsw_core_listener_unregister(struct mlxsw_core *mlxsw_core, 2513 const struct mlxsw_listener *listener, 2514 void *priv) 2515{ 2516 if (listener->is_event) 2517 mlxsw_core_event_listener_unregister(mlxsw_core, 2518 &listener->event_listener); 2519 else 2520 mlxsw_core_rx_listener_unregister(mlxsw_core, 2521 &listener->rx_listener); 2522} 2523 2524int mlxsw_core_trap_register(struct mlxsw_core *mlxsw_core, 2525 const struct mlxsw_listener *listener, void *priv) 2526{ 2527 enum mlxsw_reg_htgt_trap_group trap_group; 2528 enum mlxsw_reg_hpkt_action action; 2529 char hpkt_pl[MLXSW_REG_HPKT_LEN]; 2530 int err; 2531 2532 if (!(mlxsw_core->bus->features & MLXSW_BUS_F_TXRX)) 2533 return 0; 2534 2535 err = mlxsw_core_listener_register(mlxsw_core, listener, priv, 2536 listener->enabled_on_register); 2537 if (err) 2538 return err; 2539 2540 action = listener->enabled_on_register ? listener->en_action : 2541 listener->dis_action; 2542 trap_group = listener->enabled_on_register ? listener->en_trap_group : 2543 listener->dis_trap_group; 2544 mlxsw_reg_hpkt_pack(hpkt_pl, action, listener->trap_id, 2545 trap_group, listener->is_ctrl); 2546 err = mlxsw_reg_write(mlxsw_core, MLXSW_REG(hpkt), hpkt_pl); 2547 if (err) 2548 goto err_trap_set; 2549 2550 return 0; 2551 2552err_trap_set: 2553 mlxsw_core_listener_unregister(mlxsw_core, listener, priv); 2554 return err; 2555} 2556EXPORT_SYMBOL(mlxsw_core_trap_register); 2557 2558void mlxsw_core_trap_unregister(struct mlxsw_core *mlxsw_core, 2559 const struct mlxsw_listener *listener, 2560 void *priv) 2561{ 2562 char hpkt_pl[MLXSW_REG_HPKT_LEN]; 2563 2564 if (!(mlxsw_core->bus->features & MLXSW_BUS_F_TXRX)) 2565 return; 2566 2567 if (!listener->is_event) { 2568 mlxsw_reg_hpkt_pack(hpkt_pl, listener->dis_action, 2569 listener->trap_id, listener->dis_trap_group, 2570 listener->is_ctrl); 2571 mlxsw_reg_write(mlxsw_core, MLXSW_REG(hpkt), hpkt_pl); 2572 } 2573 2574 mlxsw_core_listener_unregister(mlxsw_core, listener, priv); 2575} 2576EXPORT_SYMBOL(mlxsw_core_trap_unregister); 2577 2578int mlxsw_core_traps_register(struct mlxsw_core *mlxsw_core, 2579 const struct mlxsw_listener *listeners, 2580 size_t listeners_count, void *priv) 2581{ 2582 int i, err; 2583 2584 for (i = 0; i < listeners_count; i++) { 2585 err = mlxsw_core_trap_register(mlxsw_core, 2586 &listeners[i], 2587 priv); 2588 if (err) 2589 goto err_listener_register; 2590 } 2591 return 0; 2592 2593err_listener_register: 2594 for (i--; i >= 0; i--) { 2595 mlxsw_core_trap_unregister(mlxsw_core, 2596 &listeners[i], 2597 priv); 2598 } 2599 return err; 2600} 2601EXPORT_SYMBOL(mlxsw_core_traps_register); 2602 2603void mlxsw_core_traps_unregister(struct mlxsw_core *mlxsw_core, 2604 const struct mlxsw_listener *listeners, 2605 size_t listeners_count, void *priv) 2606{ 2607 int i; 2608 2609 for (i = 0; i < listeners_count; i++) { 2610 mlxsw_core_trap_unregister(mlxsw_core, 2611 &listeners[i], 2612 priv); 2613 } 2614} 2615EXPORT_SYMBOL(mlxsw_core_traps_unregister); 2616 2617int mlxsw_core_trap_state_set(struct mlxsw_core *mlxsw_core, 2618 const struct mlxsw_listener *listener, 2619 bool enabled) 2620{ 2621 enum mlxsw_reg_htgt_trap_group trap_group; 2622 enum mlxsw_reg_hpkt_action action; 2623 char hpkt_pl[MLXSW_REG_HPKT_LEN]; 2624 int err; 2625 2626 /* Not supported for event listener */ 2627 if (WARN_ON(listener->is_event)) 2628 return -EINVAL; 2629 2630 action = enabled ? listener->en_action : listener->dis_action; 2631 trap_group = enabled ? listener->en_trap_group : 2632 listener->dis_trap_group; 2633 mlxsw_reg_hpkt_pack(hpkt_pl, action, listener->trap_id, 2634 trap_group, listener->is_ctrl); 2635 err = mlxsw_reg_write(mlxsw_core, MLXSW_REG(hpkt), hpkt_pl); 2636 if (err) 2637 return err; 2638 2639 mlxsw_core_rx_listener_state_set(mlxsw_core, &listener->rx_listener, 2640 enabled); 2641 return 0; 2642} 2643EXPORT_SYMBOL(mlxsw_core_trap_state_set); 2644 2645static u64 mlxsw_core_tid_get(struct mlxsw_core *mlxsw_core) 2646{ 2647 return atomic64_inc_return(&mlxsw_core->emad.tid); 2648} 2649 2650static int mlxsw_core_reg_access_emad(struct mlxsw_core *mlxsw_core, 2651 const struct mlxsw_reg_info *reg, 2652 char *payload, 2653 enum mlxsw_core_reg_access_type type, 2654 struct list_head *bulk_list, 2655 mlxsw_reg_trans_cb_t *cb, 2656 unsigned long cb_priv) 2657{ 2658 u64 tid = mlxsw_core_tid_get(mlxsw_core); 2659 struct mlxsw_reg_trans *trans; 2660 int err; 2661 2662 trans = kzalloc(sizeof(*trans), GFP_KERNEL); 2663 if (!trans) 2664 return -ENOMEM; 2665 2666 err = mlxsw_emad_reg_access(mlxsw_core, reg, payload, type, trans, 2667 bulk_list, cb, cb_priv, tid); 2668 if (err) { 2669 kfree_rcu(trans, rcu); 2670 return err; 2671 } 2672 return 0; 2673} 2674 2675int mlxsw_reg_trans_query(struct mlxsw_core *mlxsw_core, 2676 const struct mlxsw_reg_info *reg, char *payload, 2677 struct list_head *bulk_list, 2678 mlxsw_reg_trans_cb_t *cb, unsigned long cb_priv) 2679{ 2680 return mlxsw_core_reg_access_emad(mlxsw_core, reg, payload, 2681 MLXSW_CORE_REG_ACCESS_TYPE_QUERY, 2682 bulk_list, cb, cb_priv); 2683} 2684EXPORT_SYMBOL(mlxsw_reg_trans_query); 2685 2686int mlxsw_reg_trans_write(struct mlxsw_core *mlxsw_core, 2687 const struct mlxsw_reg_info *reg, char *payload, 2688 struct list_head *bulk_list, 2689 mlxsw_reg_trans_cb_t *cb, unsigned long cb_priv) 2690{ 2691 return mlxsw_core_reg_access_emad(mlxsw_core, reg, payload, 2692 MLXSW_CORE_REG_ACCESS_TYPE_WRITE, 2693 bulk_list, cb, cb_priv); 2694} 2695EXPORT_SYMBOL(mlxsw_reg_trans_write); 2696 2697#define MLXSW_REG_TRANS_ERR_STRING_SIZE 256 2698 2699static int mlxsw_reg_trans_wait(struct mlxsw_reg_trans *trans) 2700{ 2701 char err_string[MLXSW_REG_TRANS_ERR_STRING_SIZE]; 2702 struct mlxsw_core *mlxsw_core = trans->core; 2703 int err; 2704 2705 wait_for_completion(&trans->completion); 2706 cancel_delayed_work_sync(&trans->timeout_dw); 2707 err = trans->err; 2708 2709 if (trans->retries) 2710 dev_warn(mlxsw_core->bus_info->dev, "EMAD retries (%d/%d) (tid=%llx)\n", 2711 trans->retries, MLXSW_EMAD_MAX_RETRY, trans->tid); 2712 if (err) { 2713 dev_err(mlxsw_core->bus_info->dev, "EMAD reg access failed (tid=%llx,reg_id=%x(%s),type=%s,status=%x(%s))\n", 2714 trans->tid, trans->reg->id, 2715 mlxsw_reg_id_str(trans->reg->id), 2716 mlxsw_core_reg_access_type_str(trans->type), 2717 trans->emad_status, 2718 mlxsw_emad_op_tlv_status_str(trans->emad_status)); 2719 2720 snprintf(err_string, MLXSW_REG_TRANS_ERR_STRING_SIZE, 2721 "(tid=%llx,reg_id=%x(%s)) %s (%s)\n", trans->tid, 2722 trans->reg->id, mlxsw_reg_id_str(trans->reg->id), 2723 mlxsw_emad_op_tlv_status_str(trans->emad_status), 2724 trans->emad_err_string ? trans->emad_err_string : ""); 2725 2726 trace_devlink_hwerr(priv_to_devlink(mlxsw_core), 2727 trans->emad_status, err_string); 2728 2729 kfree(trans->emad_err_string); 2730 } 2731 2732 list_del(&trans->bulk_list); 2733 kfree_rcu(trans, rcu); 2734 return err; 2735} 2736 2737int mlxsw_reg_trans_bulk_wait(struct list_head *bulk_list) 2738{ 2739 struct mlxsw_reg_trans *trans; 2740 struct mlxsw_reg_trans *tmp; 2741 int sum_err = 0; 2742 int err; 2743 2744 list_for_each_entry_safe(trans, tmp, bulk_list, bulk_list) { 2745 err = mlxsw_reg_trans_wait(trans); 2746 if (err && sum_err == 0) 2747 sum_err = err; /* first error to be returned */ 2748 } 2749 return sum_err; 2750} 2751EXPORT_SYMBOL(mlxsw_reg_trans_bulk_wait); 2752 2753static int mlxsw_core_reg_access_cmd(struct mlxsw_core *mlxsw_core, 2754 const struct mlxsw_reg_info *reg, 2755 char *payload, 2756 enum mlxsw_core_reg_access_type type) 2757{ 2758 enum mlxsw_emad_op_tlv_status status; 2759 int err, n_retry; 2760 bool reset_ok; 2761 char *in_mbox, *out_mbox, *tmp; 2762 2763 dev_dbg(mlxsw_core->bus_info->dev, "Reg cmd access (reg_id=%x(%s),type=%s)\n", 2764 reg->id, mlxsw_reg_id_str(reg->id), 2765 mlxsw_core_reg_access_type_str(type)); 2766 2767 in_mbox = mlxsw_cmd_mbox_alloc(); 2768 if (!in_mbox) 2769 return -ENOMEM; 2770 2771 out_mbox = mlxsw_cmd_mbox_alloc(); 2772 if (!out_mbox) { 2773 err = -ENOMEM; 2774 goto free_in_mbox; 2775 } 2776 2777 mlxsw_emad_pack_op_tlv(in_mbox, reg, type, 2778 mlxsw_core_tid_get(mlxsw_core)); 2779 tmp = in_mbox + MLXSW_EMAD_OP_TLV_LEN * sizeof(u32); 2780 mlxsw_emad_pack_reg_tlv(tmp, reg, payload); 2781 2782 /* There is a special treatment needed for MRSR (reset) register. 2783 * The command interface will return error after the command 2784 * is executed, so tell the lower layer to expect it 2785 * and cope accordingly. 2786 */ 2787 reset_ok = reg->id == MLXSW_REG_MRSR_ID; 2788 2789 n_retry = 0; 2790retry: 2791 err = mlxsw_cmd_access_reg(mlxsw_core, reset_ok, in_mbox, out_mbox); 2792 if (!err) { 2793 err = mlxsw_emad_process_status(out_mbox, &status); 2794 if (err) { 2795 if (err == -EAGAIN && n_retry++ < MLXSW_EMAD_MAX_RETRY) 2796 goto retry; 2797 dev_err(mlxsw_core->bus_info->dev, "Reg cmd access status failed (status=%x(%s))\n", 2798 status, mlxsw_emad_op_tlv_status_str(status)); 2799 } 2800 } 2801 2802 if (!err) 2803 memcpy(payload, mlxsw_emad_reg_payload_cmd(out_mbox), 2804 reg->len); 2805 2806 mlxsw_cmd_mbox_free(out_mbox); 2807free_in_mbox: 2808 mlxsw_cmd_mbox_free(in_mbox); 2809 if (err) 2810 dev_err(mlxsw_core->bus_info->dev, "Reg cmd access failed (reg_id=%x(%s),type=%s)\n", 2811 reg->id, mlxsw_reg_id_str(reg->id), 2812 mlxsw_core_reg_access_type_str(type)); 2813 return err; 2814} 2815 2816static void mlxsw_core_reg_access_cb(struct mlxsw_core *mlxsw_core, 2817 char *payload, size_t payload_len, 2818 unsigned long cb_priv) 2819{ 2820 char *orig_payload = (char *) cb_priv; 2821 2822 memcpy(orig_payload, payload, payload_len); 2823} 2824 2825static int mlxsw_core_reg_access(struct mlxsw_core *mlxsw_core, 2826 const struct mlxsw_reg_info *reg, 2827 char *payload, 2828 enum mlxsw_core_reg_access_type type) 2829{ 2830 LIST_HEAD(bulk_list); 2831 int err; 2832 2833 /* During initialization EMAD interface is not available to us, 2834 * so we default to command interface. We switch to EMAD interface 2835 * after setting the appropriate traps. 2836 */ 2837 if (!mlxsw_core->emad.use_emad) 2838 return mlxsw_core_reg_access_cmd(mlxsw_core, reg, 2839 payload, type); 2840 2841 err = mlxsw_core_reg_access_emad(mlxsw_core, reg, 2842 payload, type, &bulk_list, 2843 mlxsw_core_reg_access_cb, 2844 (unsigned long) payload); 2845 if (err) 2846 return err; 2847 return mlxsw_reg_trans_bulk_wait(&bulk_list); 2848} 2849 2850int mlxsw_reg_query(struct mlxsw_core *mlxsw_core, 2851 const struct mlxsw_reg_info *reg, char *payload) 2852{ 2853 return mlxsw_core_reg_access(mlxsw_core, reg, payload, 2854 MLXSW_CORE_REG_ACCESS_TYPE_QUERY); 2855} 2856EXPORT_SYMBOL(mlxsw_reg_query); 2857 2858int mlxsw_reg_write(struct mlxsw_core *mlxsw_core, 2859 const struct mlxsw_reg_info *reg, char *payload) 2860{ 2861 return mlxsw_core_reg_access(mlxsw_core, reg, payload, 2862 MLXSW_CORE_REG_ACCESS_TYPE_WRITE); 2863} 2864EXPORT_SYMBOL(mlxsw_reg_write); 2865 2866void mlxsw_core_skb_receive(struct mlxsw_core *mlxsw_core, struct sk_buff *skb, 2867 struct mlxsw_rx_info *rx_info) 2868{ 2869 struct mlxsw_rx_listener_item *rxl_item; 2870 const struct mlxsw_rx_listener *rxl; 2871 u16 local_port; 2872 bool found = false; 2873 2874 if (rx_info->is_lag) { 2875 dev_dbg_ratelimited(mlxsw_core->bus_info->dev, "%s: lag_id = %d, lag_port_index = 0x%x\n", 2876 __func__, rx_info->u.lag_id, 2877 rx_info->trap_id); 2878 /* Upper layer does not care if the skb came from LAG or not, 2879 * so just get the local_port for the lag port and push it up. 2880 */ 2881 local_port = mlxsw_core_lag_mapping_get(mlxsw_core, 2882 rx_info->u.lag_id, 2883 rx_info->lag_port_index); 2884 } else { 2885 local_port = rx_info->u.sys_port; 2886 } 2887 2888 dev_dbg_ratelimited(mlxsw_core->bus_info->dev, "%s: local_port = %d, trap_id = 0x%x\n", 2889 __func__, local_port, rx_info->trap_id); 2890 2891 if ((rx_info->trap_id >= MLXSW_TRAP_ID_MAX) || 2892 (local_port >= mlxsw_core->max_ports)) 2893 goto drop; 2894 2895 rcu_read_lock(); 2896 list_for_each_entry_rcu(rxl_item, &mlxsw_core->rx_listener_list, list) { 2897 rxl = &rxl_item->rxl; 2898 if ((rxl->local_port == MLXSW_PORT_DONT_CARE || 2899 rxl->local_port == local_port) && 2900 rxl->trap_id == rx_info->trap_id && 2901 rxl->mirror_reason == rx_info->mirror_reason) { 2902 if (rxl_item->enabled) 2903 found = true; 2904 break; 2905 } 2906 } 2907 if (!found) { 2908 rcu_read_unlock(); 2909 goto drop; 2910 } 2911 2912 rxl->func(skb, local_port, rxl_item->priv); 2913 rcu_read_unlock(); 2914 return; 2915 2916drop: 2917 dev_kfree_skb(skb); 2918} 2919EXPORT_SYMBOL(mlxsw_core_skb_receive); 2920 2921static int mlxsw_core_lag_mapping_index(struct mlxsw_core *mlxsw_core, 2922 u16 lag_id, u8 port_index) 2923{ 2924 return MLXSW_CORE_RES_GET(mlxsw_core, MAX_LAG_MEMBERS) * lag_id + 2925 port_index; 2926} 2927 2928void mlxsw_core_lag_mapping_set(struct mlxsw_core *mlxsw_core, 2929 u16 lag_id, u8 port_index, u16 local_port) 2930{ 2931 int index = mlxsw_core_lag_mapping_index(mlxsw_core, 2932 lag_id, port_index); 2933 2934 mlxsw_core->lag.mapping[index] = local_port; 2935} 2936EXPORT_SYMBOL(mlxsw_core_lag_mapping_set); 2937 2938u16 mlxsw_core_lag_mapping_get(struct mlxsw_core *mlxsw_core, 2939 u16 lag_id, u8 port_index) 2940{ 2941 int index = mlxsw_core_lag_mapping_index(mlxsw_core, 2942 lag_id, port_index); 2943 2944 return mlxsw_core->lag.mapping[index]; 2945} 2946EXPORT_SYMBOL(mlxsw_core_lag_mapping_get); 2947 2948void mlxsw_core_lag_mapping_clear(struct mlxsw_core *mlxsw_core, 2949 u16 lag_id, u16 local_port) 2950{ 2951 int i; 2952 2953 for (i = 0; i < MLXSW_CORE_RES_GET(mlxsw_core, MAX_LAG_MEMBERS); i++) { 2954 int index = mlxsw_core_lag_mapping_index(mlxsw_core, 2955 lag_id, i); 2956 2957 if (mlxsw_core->lag.mapping[index] == local_port) 2958 mlxsw_core->lag.mapping[index] = 0; 2959 } 2960} 2961EXPORT_SYMBOL(mlxsw_core_lag_mapping_clear); 2962 2963bool mlxsw_core_res_valid(struct mlxsw_core *mlxsw_core, 2964 enum mlxsw_res_id res_id) 2965{ 2966 return mlxsw_res_valid(&mlxsw_core->res, res_id); 2967} 2968EXPORT_SYMBOL(mlxsw_core_res_valid); 2969 2970u64 mlxsw_core_res_get(struct mlxsw_core *mlxsw_core, 2971 enum mlxsw_res_id res_id) 2972{ 2973 return mlxsw_res_get(&mlxsw_core->res, res_id); 2974} 2975EXPORT_SYMBOL(mlxsw_core_res_get); 2976 2977static int __mlxsw_core_port_init(struct mlxsw_core *mlxsw_core, u16 local_port, 2978 enum devlink_port_flavour flavour, 2979 u8 slot_index, u32 port_number, bool split, 2980 u32 split_port_subnumber, 2981 bool splittable, u32 lanes, 2982 const unsigned char *switch_id, 2983 unsigned char switch_id_len) 2984{ 2985 struct devlink *devlink = priv_to_devlink(mlxsw_core); 2986 struct mlxsw_core_port *mlxsw_core_port = 2987 &mlxsw_core->ports[local_port]; 2988 struct devlink_port *devlink_port = &mlxsw_core_port->devlink_port; 2989 struct devlink_port_attrs attrs = {}; 2990 int err; 2991 2992 attrs.split = split; 2993 attrs.lanes = lanes; 2994 attrs.splittable = splittable; 2995 attrs.flavour = flavour; 2996 attrs.phys.port_number = port_number; 2997 attrs.phys.split_subport_number = split_port_subnumber; 2998 memcpy(attrs.switch_id.id, switch_id, switch_id_len); 2999 attrs.switch_id.id_len = switch_id_len; 3000 mlxsw_core_port->local_port = local_port; 3001 devlink_port_attrs_set(devlink_port, &attrs); 3002 if (slot_index) { 3003 struct mlxsw_linecard *linecard; 3004 3005 linecard = mlxsw_linecard_get(mlxsw_core->linecards, 3006 slot_index); 3007 mlxsw_core_port->linecard = linecard; 3008 devlink_port_linecard_set(devlink_port, 3009 linecard->devlink_linecard); 3010 } 3011 err = devl_port_register(devlink, devlink_port, local_port); 3012 if (err) 3013 memset(mlxsw_core_port, 0, sizeof(*mlxsw_core_port)); 3014 return err; 3015} 3016 3017static void __mlxsw_core_port_fini(struct mlxsw_core *mlxsw_core, u16 local_port) 3018{ 3019 struct mlxsw_core_port *mlxsw_core_port = 3020 &mlxsw_core->ports[local_port]; 3021 struct devlink_port *devlink_port = &mlxsw_core_port->devlink_port; 3022 3023 devl_port_unregister(devlink_port); 3024 memset(mlxsw_core_port, 0, sizeof(*mlxsw_core_port)); 3025} 3026 3027int mlxsw_core_port_init(struct mlxsw_core *mlxsw_core, u16 local_port, 3028 u8 slot_index, u32 port_number, bool split, 3029 u32 split_port_subnumber, 3030 bool splittable, u32 lanes, 3031 const unsigned char *switch_id, 3032 unsigned char switch_id_len) 3033{ 3034 int err; 3035 3036 err = __mlxsw_core_port_init(mlxsw_core, local_port, 3037 DEVLINK_PORT_FLAVOUR_PHYSICAL, slot_index, 3038 port_number, split, split_port_subnumber, 3039 splittable, lanes, 3040 switch_id, switch_id_len); 3041 if (err) 3042 return err; 3043 3044 atomic_inc(&mlxsw_core->active_ports_count); 3045 return 0; 3046} 3047EXPORT_SYMBOL(mlxsw_core_port_init); 3048 3049void mlxsw_core_port_fini(struct mlxsw_core *mlxsw_core, u16 local_port) 3050{ 3051 atomic_dec(&mlxsw_core->active_ports_count); 3052 3053 __mlxsw_core_port_fini(mlxsw_core, local_port); 3054} 3055EXPORT_SYMBOL(mlxsw_core_port_fini); 3056 3057int mlxsw_core_cpu_port_init(struct mlxsw_core *mlxsw_core, 3058 void *port_driver_priv, 3059 const unsigned char *switch_id, 3060 unsigned char switch_id_len) 3061{ 3062 struct mlxsw_core_port *mlxsw_core_port = 3063 &mlxsw_core->ports[MLXSW_PORT_CPU_PORT]; 3064 int err; 3065 3066 err = __mlxsw_core_port_init(mlxsw_core, MLXSW_PORT_CPU_PORT, 3067 DEVLINK_PORT_FLAVOUR_CPU, 3068 0, 0, false, 0, false, 0, 3069 switch_id, switch_id_len); 3070 if (err) 3071 return err; 3072 3073 mlxsw_core_port->port_driver_priv = port_driver_priv; 3074 return 0; 3075} 3076EXPORT_SYMBOL(mlxsw_core_cpu_port_init); 3077 3078void mlxsw_core_cpu_port_fini(struct mlxsw_core *mlxsw_core) 3079{ 3080 __mlxsw_core_port_fini(mlxsw_core, MLXSW_PORT_CPU_PORT); 3081} 3082EXPORT_SYMBOL(mlxsw_core_cpu_port_fini); 3083 3084void mlxsw_core_port_eth_set(struct mlxsw_core *mlxsw_core, u16 local_port, 3085 void *port_driver_priv, struct net_device *dev) 3086{ 3087 struct mlxsw_core_port *mlxsw_core_port = 3088 &mlxsw_core->ports[local_port]; 3089 struct devlink_port *devlink_port = &mlxsw_core_port->devlink_port; 3090 3091 mlxsw_core_port->port_driver_priv = port_driver_priv; 3092 devlink_port_type_eth_set(devlink_port, dev); 3093} 3094EXPORT_SYMBOL(mlxsw_core_port_eth_set); 3095 3096void mlxsw_core_port_ib_set(struct mlxsw_core *mlxsw_core, u16 local_port, 3097 void *port_driver_priv) 3098{ 3099 struct mlxsw_core_port *mlxsw_core_port = 3100 &mlxsw_core->ports[local_port]; 3101 struct devlink_port *devlink_port = &mlxsw_core_port->devlink_port; 3102 3103 mlxsw_core_port->port_driver_priv = port_driver_priv; 3104 devlink_port_type_ib_set(devlink_port, NULL); 3105} 3106EXPORT_SYMBOL(mlxsw_core_port_ib_set); 3107 3108void mlxsw_core_port_clear(struct mlxsw_core *mlxsw_core, u16 local_port, 3109 void *port_driver_priv) 3110{ 3111 struct mlxsw_core_port *mlxsw_core_port = 3112 &mlxsw_core->ports[local_port]; 3113 struct devlink_port *devlink_port = &mlxsw_core_port->devlink_port; 3114 3115 mlxsw_core_port->port_driver_priv = port_driver_priv; 3116 devlink_port_type_clear(devlink_port); 3117} 3118EXPORT_SYMBOL(mlxsw_core_port_clear); 3119 3120enum devlink_port_type mlxsw_core_port_type_get(struct mlxsw_core *mlxsw_core, 3121 u16 local_port) 3122{ 3123 struct mlxsw_core_port *mlxsw_core_port = 3124 &mlxsw_core->ports[local_port]; 3125 struct devlink_port *devlink_port = &mlxsw_core_port->devlink_port; 3126 3127 return devlink_port->type; 3128} 3129EXPORT_SYMBOL(mlxsw_core_port_type_get); 3130 3131 3132struct devlink_port * 3133mlxsw_core_port_devlink_port_get(struct mlxsw_core *mlxsw_core, 3134 u16 local_port) 3135{ 3136 struct mlxsw_core_port *mlxsw_core_port = 3137 &mlxsw_core->ports[local_port]; 3138 struct devlink_port *devlink_port = &mlxsw_core_port->devlink_port; 3139 3140 return devlink_port; 3141} 3142EXPORT_SYMBOL(mlxsw_core_port_devlink_port_get); 3143 3144struct mlxsw_linecard * 3145mlxsw_core_port_linecard_get(struct mlxsw_core *mlxsw_core, 3146 u16 local_port) 3147{ 3148 struct mlxsw_core_port *mlxsw_core_port = 3149 &mlxsw_core->ports[local_port]; 3150 3151 return mlxsw_core_port->linecard; 3152} 3153 3154bool mlxsw_core_port_is_xm(const struct mlxsw_core *mlxsw_core, u16 local_port) 3155{ 3156 const struct mlxsw_bus_info *bus_info = mlxsw_core->bus_info; 3157 int i; 3158 3159 for (i = 0; i < bus_info->xm_local_ports_count; i++) 3160 if (bus_info->xm_local_ports[i] == local_port) 3161 return true; 3162 return false; 3163} 3164EXPORT_SYMBOL(mlxsw_core_port_is_xm); 3165 3166void mlxsw_core_ports_remove_selected(struct mlxsw_core *mlxsw_core, 3167 bool (*selector)(void *priv, u16 local_port), 3168 void *priv) 3169{ 3170 if (WARN_ON_ONCE(!mlxsw_core->driver->ports_remove_selected)) 3171 return; 3172 mlxsw_core->driver->ports_remove_selected(mlxsw_core, selector, priv); 3173} 3174 3175struct mlxsw_env *mlxsw_core_env(const struct mlxsw_core *mlxsw_core) 3176{ 3177 return mlxsw_core->env; 3178} 3179 3180static void mlxsw_core_buf_dump_dbg(struct mlxsw_core *mlxsw_core, 3181 const char *buf, size_t size) 3182{ 3183 __be32 *m = (__be32 *) buf; 3184 int i; 3185 int count = size / sizeof(__be32); 3186 3187 for (i = count - 1; i >= 0; i--) 3188 if (m[i]) 3189 break; 3190 i++; 3191 count = i ? i : 1; 3192 for (i = 0; i < count; i += 4) 3193 dev_dbg(mlxsw_core->bus_info->dev, "%04x - %08x %08x %08x %08x\n", 3194 i * 4, be32_to_cpu(m[i]), be32_to_cpu(m[i + 1]), 3195 be32_to_cpu(m[i + 2]), be32_to_cpu(m[i + 3])); 3196} 3197 3198int mlxsw_cmd_exec(struct mlxsw_core *mlxsw_core, u16 opcode, u8 opcode_mod, 3199 u32 in_mod, bool out_mbox_direct, bool reset_ok, 3200 char *in_mbox, size_t in_mbox_size, 3201 char *out_mbox, size_t out_mbox_size) 3202{ 3203 u8 status; 3204 int err; 3205 3206 BUG_ON(in_mbox_size % sizeof(u32) || out_mbox_size % sizeof(u32)); 3207 if (!mlxsw_core->bus->cmd_exec) 3208 return -EOPNOTSUPP; 3209 3210 dev_dbg(mlxsw_core->bus_info->dev, "Cmd exec (opcode=%x(%s),opcode_mod=%x,in_mod=%x)\n", 3211 opcode, mlxsw_cmd_opcode_str(opcode), opcode_mod, in_mod); 3212 if (in_mbox) { 3213 dev_dbg(mlxsw_core->bus_info->dev, "Input mailbox:\n"); 3214 mlxsw_core_buf_dump_dbg(mlxsw_core, in_mbox, in_mbox_size); 3215 } 3216 3217 err = mlxsw_core->bus->cmd_exec(mlxsw_core->bus_priv, opcode, 3218 opcode_mod, in_mod, out_mbox_direct, 3219 in_mbox, in_mbox_size, 3220 out_mbox, out_mbox_size, &status); 3221 3222 if (!err && out_mbox) { 3223 dev_dbg(mlxsw_core->bus_info->dev, "Output mailbox:\n"); 3224 mlxsw_core_buf_dump_dbg(mlxsw_core, out_mbox, out_mbox_size); 3225 } 3226 3227 if (reset_ok && err == -EIO && 3228 status == MLXSW_CMD_STATUS_RUNNING_RESET) { 3229 err = 0; 3230 } else if (err == -EIO && status != MLXSW_CMD_STATUS_OK) { 3231 dev_err(mlxsw_core->bus_info->dev, "Cmd exec failed (opcode=%x(%s),opcode_mod=%x,in_mod=%x,status=%x(%s))\n", 3232 opcode, mlxsw_cmd_opcode_str(opcode), opcode_mod, 3233 in_mod, status, mlxsw_cmd_status_str(status)); 3234 } else if (err == -ETIMEDOUT) { 3235 dev_err(mlxsw_core->bus_info->dev, "Cmd exec timed-out (opcode=%x(%s),opcode_mod=%x,in_mod=%x)\n", 3236 opcode, mlxsw_cmd_opcode_str(opcode), opcode_mod, 3237 in_mod); 3238 } 3239 3240 return err; 3241} 3242EXPORT_SYMBOL(mlxsw_cmd_exec); 3243 3244int mlxsw_core_schedule_dw(struct delayed_work *dwork, unsigned long delay) 3245{ 3246 return queue_delayed_work(mlxsw_wq, dwork, delay); 3247} 3248EXPORT_SYMBOL(mlxsw_core_schedule_dw); 3249 3250bool mlxsw_core_schedule_work(struct work_struct *work) 3251{ 3252 return queue_work(mlxsw_owq, work); 3253} 3254EXPORT_SYMBOL(mlxsw_core_schedule_work); 3255 3256void mlxsw_core_flush_owq(void) 3257{ 3258 flush_workqueue(mlxsw_owq); 3259} 3260EXPORT_SYMBOL(mlxsw_core_flush_owq); 3261 3262int mlxsw_core_kvd_sizes_get(struct mlxsw_core *mlxsw_core, 3263 const struct mlxsw_config_profile *profile, 3264 u64 *p_single_size, u64 *p_double_size, 3265 u64 *p_linear_size) 3266{ 3267 struct mlxsw_driver *driver = mlxsw_core->driver; 3268 3269 if (!driver->kvd_sizes_get) 3270 return -EINVAL; 3271 3272 return driver->kvd_sizes_get(mlxsw_core, profile, 3273 p_single_size, p_double_size, 3274 p_linear_size); 3275} 3276EXPORT_SYMBOL(mlxsw_core_kvd_sizes_get); 3277 3278int mlxsw_core_resources_query(struct mlxsw_core *mlxsw_core, char *mbox, 3279 struct mlxsw_res *res) 3280{ 3281 int index, i; 3282 u64 data; 3283 u16 id; 3284 int err; 3285 3286 mlxsw_cmd_mbox_zero(mbox); 3287 3288 for (index = 0; index < MLXSW_CMD_QUERY_RESOURCES_MAX_QUERIES; 3289 index++) { 3290 err = mlxsw_cmd_query_resources(mlxsw_core, mbox, index); 3291 if (err) 3292 return err; 3293 3294 for (i = 0; i < MLXSW_CMD_QUERY_RESOURCES_PER_QUERY; i++) { 3295 id = mlxsw_cmd_mbox_query_resource_id_get(mbox, i); 3296 data = mlxsw_cmd_mbox_query_resource_data_get(mbox, i); 3297 3298 if (id == MLXSW_CMD_QUERY_RESOURCES_TABLE_END_ID) 3299 return 0; 3300 3301 mlxsw_res_parse(res, id, data); 3302 } 3303 } 3304 3305 /* If after MLXSW_RESOURCES_QUERY_MAX_QUERIES we still didn't get 3306 * MLXSW_RESOURCES_TABLE_END_ID, something went bad in the FW. 3307 */ 3308 return -EIO; 3309} 3310EXPORT_SYMBOL(mlxsw_core_resources_query); 3311 3312u32 mlxsw_core_read_frc_h(struct mlxsw_core *mlxsw_core) 3313{ 3314 return mlxsw_core->bus->read_frc_h(mlxsw_core->bus_priv); 3315} 3316EXPORT_SYMBOL(mlxsw_core_read_frc_h); 3317 3318u32 mlxsw_core_read_frc_l(struct mlxsw_core *mlxsw_core) 3319{ 3320 return mlxsw_core->bus->read_frc_l(mlxsw_core->bus_priv); 3321} 3322EXPORT_SYMBOL(mlxsw_core_read_frc_l); 3323 3324void mlxsw_core_emad_string_tlv_enable(struct mlxsw_core *mlxsw_core) 3325{ 3326 mlxsw_core->emad.enable_string_tlv = true; 3327} 3328EXPORT_SYMBOL(mlxsw_core_emad_string_tlv_enable); 3329 3330static int __init mlxsw_core_module_init(void) 3331{ 3332 int err; 3333 3334 mlxsw_wq = alloc_workqueue(mlxsw_core_driver_name, 0, 0); 3335 if (!mlxsw_wq) 3336 return -ENOMEM; 3337 mlxsw_owq = alloc_ordered_workqueue("%s_ordered", 0, 3338 mlxsw_core_driver_name); 3339 if (!mlxsw_owq) { 3340 err = -ENOMEM; 3341 goto err_alloc_ordered_workqueue; 3342 } 3343 return 0; 3344 3345err_alloc_ordered_workqueue: 3346 destroy_workqueue(mlxsw_wq); 3347 return err; 3348} 3349 3350static void __exit mlxsw_core_module_exit(void) 3351{ 3352 destroy_workqueue(mlxsw_owq); 3353 destroy_workqueue(mlxsw_wq); 3354} 3355 3356module_init(mlxsw_core_module_init); 3357module_exit(mlxsw_core_module_exit); 3358 3359MODULE_LICENSE("Dual BSD/GPL"); 3360MODULE_AUTHOR("Jiri Pirko <jiri@mellanox.com>"); 3361MODULE_DESCRIPTION("Mellanox switch device core driver");