1 // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0 2 /* Copyright (c) 2018 Mellanox Technologies. All rights reserved */ 3 4 #include <linux/if_bridge.h> 5 #include <linux/list.h> 6 #include <linux/mutex.h> 7 #include <linux/refcount.h> 8 #include <linux/rtnetlink.h> 9 #include <linux/workqueue.h> 10 #include <net/arp.h> 11 #include <net/gre.h> 12 #include <net/lag.h> 13 #include <net/ndisc.h> 14 #include <net/ip6_tunnel.h> 15 16 #include "spectrum.h" 17 #include "spectrum_ipip.h" 18 #include "spectrum_span.h" 19 #include "spectrum_switchdev.h" 20 21 struct mlxsw_sp_span { 22 struct work_struct work; 23 struct mlxsw_sp *mlxsw_sp; 24 const struct mlxsw_sp_span_trigger_ops **span_trigger_ops_arr; 25 const struct mlxsw_sp_span_entry_ops **span_entry_ops_arr; 26 size_t span_entry_ops_arr_size; 27 struct list_head analyzed_ports_list; 28 struct mutex analyzed_ports_lock; /* Protects analyzed_ports_list */ 29 struct list_head trigger_entries_list; 30 u16 policer_id_base; 31 refcount_t policer_id_base_ref_count; 32 atomic_t active_entries_count; 33 int entries_count; 34 struct mlxsw_sp_span_entry entries[] __counted_by(entries_count); 35 }; 36 37 struct mlxsw_sp_span_analyzed_port { 38 struct list_head list; /* Member of analyzed_ports_list */ 39 refcount_t ref_count; 40 u16 local_port; 41 bool ingress; 42 }; 43 44 struct mlxsw_sp_span_trigger_entry { 45 struct list_head list; /* Member of trigger_entries_list */ 46 struct mlxsw_sp_span *span; 47 const struct mlxsw_sp_span_trigger_ops *ops; 48 refcount_t ref_count; 49 u16 local_port; 50 enum mlxsw_sp_span_trigger trigger; 51 struct mlxsw_sp_span_trigger_parms parms; 52 }; 53 54 enum mlxsw_sp_span_trigger_type { 55 MLXSW_SP_SPAN_TRIGGER_TYPE_PORT, 56 MLXSW_SP_SPAN_TRIGGER_TYPE_GLOBAL, 57 }; 58 59 struct mlxsw_sp_span_trigger_ops { 60 int (*bind)(struct mlxsw_sp_span_trigger_entry *trigger_entry); 61 void (*unbind)(struct mlxsw_sp_span_trigger_entry *trigger_entry); 62 bool (*matches)(struct mlxsw_sp_span_trigger_entry *trigger_entry, 63 enum mlxsw_sp_span_trigger trigger, 64 struct mlxsw_sp_port *mlxsw_sp_port); 65 int (*enable)(struct mlxsw_sp_span_trigger_entry *trigger_entry, 66 struct mlxsw_sp_port *mlxsw_sp_port, u8 tc); 67 void (*disable)(struct mlxsw_sp_span_trigger_entry *trigger_entry, 68 struct mlxsw_sp_port *mlxsw_sp_port, u8 tc); 69 }; 70 71 static void mlxsw_sp_span_respin_work(struct work_struct *work); 72 73 static u64 mlxsw_sp_span_occ_get(void *priv) 74 { 75 const struct mlxsw_sp *mlxsw_sp = priv; 76 77 return atomic_read(&mlxsw_sp->span->active_entries_count); 78 } 79 80 int mlxsw_sp_span_init(struct mlxsw_sp *mlxsw_sp) 81 { 82 struct devlink *devlink = priv_to_devlink(mlxsw_sp->core); 83 struct mlxsw_sp_span *span; 84 int i, entries_count, err; 85 86 if (!MLXSW_CORE_RES_VALID(mlxsw_sp->core, MAX_SPAN)) 87 return -EIO; 88 89 entries_count = MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_SPAN); 90 span = kzalloc_flex(*span, entries, entries_count); 91 if (!span) 92 return -ENOMEM; 93 refcount_set(&span->policer_id_base_ref_count, 0); 94 span->entries_count = entries_count; 95 atomic_set(&span->active_entries_count, 0); 96 mutex_init(&span->analyzed_ports_lock); 97 INIT_LIST_HEAD(&span->analyzed_ports_list); 98 INIT_LIST_HEAD(&span->trigger_entries_list); 99 span->mlxsw_sp = mlxsw_sp; 100 mlxsw_sp->span = span; 101 102 for (i = 0; i < mlxsw_sp->span->entries_count; i++) 103 mlxsw_sp->span->entries[i].id = i; 104 105 err = mlxsw_sp->span_ops->init(mlxsw_sp); 106 if (err) 107 goto err_init; 108 109 devl_resource_occ_get_register(devlink, MLXSW_SP_RESOURCE_SPAN, 110 mlxsw_sp_span_occ_get, mlxsw_sp); 111 INIT_WORK(&span->work, mlxsw_sp_span_respin_work); 112 113 return 0; 114 115 err_init: 116 mutex_destroy(&mlxsw_sp->span->analyzed_ports_lock); 117 kfree(mlxsw_sp->span); 118 return err; 119 } 120 121 void mlxsw_sp_span_fini(struct mlxsw_sp *mlxsw_sp) 122 { 123 struct devlink *devlink = priv_to_devlink(mlxsw_sp->core); 124 125 cancel_work_sync(&mlxsw_sp->span->work); 126 devl_resource_occ_get_unregister(devlink, MLXSW_SP_RESOURCE_SPAN); 127 128 WARN_ON_ONCE(!list_empty(&mlxsw_sp->span->trigger_entries_list)); 129 WARN_ON_ONCE(!list_empty(&mlxsw_sp->span->analyzed_ports_list)); 130 mutex_destroy(&mlxsw_sp->span->analyzed_ports_lock); 131 kfree(mlxsw_sp->span); 132 } 133 134 static bool mlxsw_sp1_span_cpu_can_handle(const struct net_device *dev) 135 { 136 return !dev; 137 } 138 139 static int mlxsw_sp1_span_entry_cpu_parms(struct mlxsw_sp *mlxsw_sp, 140 const struct net_device *to_dev, 141 struct mlxsw_sp_span_parms *sparmsp) 142 { 143 return -EOPNOTSUPP; 144 } 145 146 static int 147 mlxsw_sp1_span_entry_cpu_configure(struct mlxsw_sp_span_entry *span_entry, 148 struct mlxsw_sp_span_parms sparms) 149 { 150 return -EOPNOTSUPP; 151 } 152 153 static void 154 mlxsw_sp1_span_entry_cpu_deconfigure(struct mlxsw_sp_span_entry *span_entry) 155 { 156 } 157 158 static const 159 struct mlxsw_sp_span_entry_ops mlxsw_sp1_span_entry_ops_cpu = { 160 .is_static = true, 161 .can_handle = mlxsw_sp1_span_cpu_can_handle, 162 .parms_set = mlxsw_sp1_span_entry_cpu_parms, 163 .configure = mlxsw_sp1_span_entry_cpu_configure, 164 .deconfigure = mlxsw_sp1_span_entry_cpu_deconfigure, 165 }; 166 167 static int 168 mlxsw_sp_span_entry_phys_parms(struct mlxsw_sp *mlxsw_sp, 169 const struct net_device *to_dev, 170 struct mlxsw_sp_span_parms *sparmsp) 171 { 172 sparmsp->dest_port = netdev_priv(to_dev); 173 return 0; 174 } 175 176 static int 177 mlxsw_sp_span_entry_phys_configure(struct mlxsw_sp_span_entry *span_entry, 178 struct mlxsw_sp_span_parms sparms) 179 { 180 struct mlxsw_sp_port *dest_port = sparms.dest_port; 181 struct mlxsw_sp *mlxsw_sp = dest_port->mlxsw_sp; 182 u16 local_port = dest_port->local_port; 183 char mpat_pl[MLXSW_REG_MPAT_LEN]; 184 int pa_id = span_entry->id; 185 186 /* Create a new port analayzer entry for local_port. */ 187 mlxsw_reg_mpat_pack(mpat_pl, pa_id, local_port, true, 188 MLXSW_REG_MPAT_SPAN_TYPE_LOCAL_ETH); 189 mlxsw_reg_mpat_session_id_set(mpat_pl, sparms.session_id); 190 mlxsw_reg_mpat_pide_set(mpat_pl, sparms.policer_enable); 191 mlxsw_reg_mpat_pid_set(mpat_pl, sparms.policer_id); 192 193 return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(mpat), mpat_pl); 194 } 195 196 static void 197 mlxsw_sp_span_entry_deconfigure_common(struct mlxsw_sp_span_entry *span_entry, 198 enum mlxsw_reg_mpat_span_type span_type) 199 { 200 struct mlxsw_sp_port *dest_port = span_entry->parms.dest_port; 201 struct mlxsw_sp *mlxsw_sp = dest_port->mlxsw_sp; 202 u16 local_port = dest_port->local_port; 203 char mpat_pl[MLXSW_REG_MPAT_LEN]; 204 int pa_id = span_entry->id; 205 206 mlxsw_reg_mpat_pack(mpat_pl, pa_id, local_port, false, span_type); 207 mlxsw_reg_mpat_session_id_set(mpat_pl, span_entry->parms.session_id); 208 mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(mpat), mpat_pl); 209 } 210 211 static void 212 mlxsw_sp_span_entry_phys_deconfigure(struct mlxsw_sp_span_entry *span_entry) 213 { 214 mlxsw_sp_span_entry_deconfigure_common(span_entry, 215 MLXSW_REG_MPAT_SPAN_TYPE_LOCAL_ETH); 216 } 217 218 static const 219 struct mlxsw_sp_span_entry_ops mlxsw_sp_span_entry_ops_phys = { 220 .is_static = true, 221 .can_handle = mlxsw_sp_port_dev_check, 222 .parms_set = mlxsw_sp_span_entry_phys_parms, 223 .configure = mlxsw_sp_span_entry_phys_configure, 224 .deconfigure = mlxsw_sp_span_entry_phys_deconfigure, 225 }; 226 227 static int mlxsw_sp_span_dmac(int family, 228 const void *pkey, 229 struct net_device *dev, 230 unsigned char dmac[ETH_ALEN]) 231 { 232 struct neighbour *neigh; 233 int err = 0; 234 235 #if IS_ENABLED(CONFIG_IPV6_GRE) 236 if (family == AF_INET6) { 237 neigh = ipv6_neigh_lookup(dev, pkey); 238 if (!neigh) { 239 neigh = ipv6_neigh_create(dev, pkey); 240 if (IS_ERR(neigh)) 241 return PTR_ERR(neigh); 242 } 243 } else 244 #endif 245 { 246 neigh = ipv4_neigh_lookup(dev, pkey); 247 if (!neigh) { 248 neigh = ipv4_neigh_create(dev, pkey); 249 if (IS_ERR(neigh)) 250 return PTR_ERR(neigh); 251 } 252 } 253 254 neigh_event_send(neigh, NULL); 255 256 read_lock_bh(&neigh->lock); 257 if ((neigh->nud_state & NUD_VALID) && !neigh->dead) 258 memcpy(dmac, neigh->ha, ETH_ALEN); 259 else 260 err = -ENOENT; 261 read_unlock_bh(&neigh->lock); 262 263 neigh_release(neigh); 264 return err; 265 } 266 267 static int 268 mlxsw_sp_span_entry_unoffloadable(struct mlxsw_sp_span_parms *sparmsp) 269 { 270 sparmsp->dest_port = NULL; 271 return 0; 272 } 273 274 static struct net_device * 275 mlxsw_sp_span_entry_bridge_8021q(const struct net_device *br_dev, 276 unsigned char *dmac, 277 u16 *p_vid) 278 { 279 struct bridge_vlan_info vinfo; 280 struct net_device *edev; 281 u16 vid = *p_vid; 282 283 if (!vid && WARN_ON(br_vlan_get_pvid(br_dev, &vid))) 284 return NULL; 285 if (!vid || br_vlan_get_info(br_dev, vid, &vinfo) || 286 !(vinfo.flags & BRIDGE_VLAN_INFO_BRENTRY)) 287 return NULL; 288 289 edev = br_fdb_find_port(br_dev, dmac, vid); 290 if (!edev) 291 return NULL; 292 293 if (br_vlan_get_info(edev, vid, &vinfo)) 294 return NULL; 295 if (vinfo.flags & BRIDGE_VLAN_INFO_UNTAGGED) 296 *p_vid = 0; 297 else 298 *p_vid = vid; 299 return edev; 300 } 301 302 static struct net_device * 303 mlxsw_sp_span_entry_bridge_8021d(const struct net_device *br_dev, 304 unsigned char *dmac) 305 { 306 return br_fdb_find_port(br_dev, dmac, 0); 307 } 308 309 static struct net_device * 310 mlxsw_sp_span_entry_bridge(const struct net_device *br_dev, 311 unsigned char dmac[ETH_ALEN], 312 u16 *p_vid) 313 { 314 struct mlxsw_sp_bridge_port *bridge_port; 315 enum mlxsw_reg_spms_state spms_state; 316 struct net_device *dev = NULL; 317 struct mlxsw_sp_port *port; 318 u8 stp_state; 319 320 if (br_vlan_enabled(br_dev)) 321 dev = mlxsw_sp_span_entry_bridge_8021q(br_dev, dmac, p_vid); 322 else if (!*p_vid) 323 dev = mlxsw_sp_span_entry_bridge_8021d(br_dev, dmac); 324 if (!dev) 325 return NULL; 326 327 port = mlxsw_sp_port_dev_lower_find(dev); 328 if (!port) 329 return NULL; 330 331 bridge_port = mlxsw_sp_bridge_port_find(port->mlxsw_sp->bridge, dev); 332 if (!bridge_port) 333 return NULL; 334 335 stp_state = mlxsw_sp_bridge_port_stp_state(bridge_port); 336 spms_state = mlxsw_sp_stp_spms_state(stp_state); 337 if (spms_state != MLXSW_REG_SPMS_STATE_FORWARDING) 338 return NULL; 339 340 return dev; 341 } 342 343 static struct net_device * 344 mlxsw_sp_span_entry_vlan(const struct net_device *vlan_dev, 345 u16 *p_vid) 346 { 347 *p_vid = vlan_dev_vlan_id(vlan_dev); 348 return vlan_dev_real_dev(vlan_dev); 349 } 350 351 static struct net_device * 352 mlxsw_sp_span_entry_lag(struct net_device *lag_dev) 353 { 354 struct net_device *dev; 355 struct list_head *iter; 356 357 netdev_for_each_lower_dev(lag_dev, dev, iter) 358 if (netif_carrier_ok(dev) && 359 net_lag_port_dev_txable(dev) && 360 mlxsw_sp_port_dev_check(dev)) 361 return dev; 362 363 return NULL; 364 } 365 366 static __maybe_unused int 367 mlxsw_sp_span_entry_tunnel_parms_common(struct net_device *edev, 368 union mlxsw_sp_l3addr saddr, 369 union mlxsw_sp_l3addr daddr, 370 union mlxsw_sp_l3addr gw, 371 __u8 ttl, int family, 372 struct mlxsw_sp_span_parms *sparmsp) 373 { 374 unsigned char dmac[ETH_ALEN]; 375 u16 vid = 0; 376 377 if (mlxsw_sp_l3addr_is_zero(gw)) 378 gw = daddr; 379 380 if (!edev || mlxsw_sp_span_dmac(family, &gw, edev, dmac)) 381 goto unoffloadable; 382 383 if (is_vlan_dev(edev)) 384 edev = mlxsw_sp_span_entry_vlan(edev, &vid); 385 386 if (netif_is_bridge_master(edev)) { 387 edev = mlxsw_sp_span_entry_bridge(edev, dmac, &vid); 388 if (!edev) 389 goto unoffloadable; 390 } 391 392 if (is_vlan_dev(edev)) { 393 if (vid || !(edev->flags & IFF_UP)) 394 goto unoffloadable; 395 edev = mlxsw_sp_span_entry_vlan(edev, &vid); 396 } 397 398 if (netif_is_lag_master(edev)) { 399 if (!(edev->flags & IFF_UP)) 400 goto unoffloadable; 401 edev = mlxsw_sp_span_entry_lag(edev); 402 if (!edev) 403 goto unoffloadable; 404 } 405 406 if (!mlxsw_sp_port_dev_check(edev)) 407 goto unoffloadable; 408 409 sparmsp->dest_port = netdev_priv(edev); 410 sparmsp->ttl = ttl; 411 memcpy(sparmsp->dmac, dmac, ETH_ALEN); 412 memcpy(sparmsp->smac, edev->dev_addr, ETH_ALEN); 413 sparmsp->saddr = saddr; 414 sparmsp->daddr = daddr; 415 sparmsp->vid = vid; 416 return 0; 417 418 unoffloadable: 419 return mlxsw_sp_span_entry_unoffloadable(sparmsp); 420 } 421 422 #if IS_ENABLED(CONFIG_NET_IPGRE) 423 static struct net_device * 424 mlxsw_sp_span_gretap4_route(const struct net_device *to_dev, 425 __be32 *saddrp, __be32 *daddrp) 426 { 427 struct ip_tunnel *tun = netdev_priv(to_dev); 428 struct ip_tunnel_parm_kern parms; 429 struct net_device *dev = NULL; 430 struct rtable *rt = NULL; 431 struct flowi4 fl4; 432 433 /* We assume "dev" stays valid after rt is put. */ 434 ASSERT_RTNL(); 435 436 parms = mlxsw_sp_ipip_netdev_parms4(to_dev); 437 ip_tunnel_init_flow(&fl4, parms.iph.protocol, *daddrp, *saddrp, 438 0, 0, tun->net, parms.link, tun->fwmark, 0, 0); 439 440 rt = ip_route_output_key(tun->net, &fl4); 441 if (IS_ERR(rt)) 442 return NULL; 443 444 if (rt->rt_type != RTN_UNICAST) 445 goto out; 446 447 dev = rt->dst.dev; 448 *saddrp = fl4.saddr; 449 if (rt->rt_gw_family == AF_INET) 450 *daddrp = rt->rt_gw4; 451 /* can not offload if route has an IPv6 gateway */ 452 else if (rt->rt_gw_family == AF_INET6) 453 dev = NULL; 454 455 out: 456 ip_rt_put(rt); 457 return dev; 458 } 459 460 static int 461 mlxsw_sp_span_entry_gretap4_parms(struct mlxsw_sp *mlxsw_sp, 462 const struct net_device *to_dev, 463 struct mlxsw_sp_span_parms *sparmsp) 464 { 465 struct ip_tunnel_parm_kern tparm = mlxsw_sp_ipip_netdev_parms4(to_dev); 466 union mlxsw_sp_l3addr saddr = { .addr4 = tparm.iph.saddr }; 467 union mlxsw_sp_l3addr daddr = { .addr4 = tparm.iph.daddr }; 468 bool inherit_tos = tparm.iph.tos & 0x1; 469 bool inherit_ttl = !tparm.iph.ttl; 470 union mlxsw_sp_l3addr gw = daddr; 471 struct net_device *l3edev; 472 473 if (!(to_dev->flags & IFF_UP) || 474 /* Reject tunnels with GRE keys, checksums, etc. */ 475 !ip_tunnel_flags_empty(tparm.i_flags) || 476 !ip_tunnel_flags_empty(tparm.o_flags) || 477 /* Require a fixed TTL and a TOS copied from the mirrored packet. */ 478 inherit_ttl || !inherit_tos || 479 /* A destination address may not be "any". */ 480 mlxsw_sp_l3addr_is_zero(daddr)) 481 return mlxsw_sp_span_entry_unoffloadable(sparmsp); 482 483 l3edev = mlxsw_sp_span_gretap4_route(to_dev, &saddr.addr4, &gw.addr4); 484 485 return mlxsw_sp_span_entry_tunnel_parms_common(l3edev, saddr, daddr, gw, 486 tparm.iph.ttl, 487 AF_INET, sparmsp); 488 } 489 490 static int 491 mlxsw_sp_span_entry_gretap4_configure(struct mlxsw_sp_span_entry *span_entry, 492 struct mlxsw_sp_span_parms sparms) 493 { 494 struct mlxsw_sp_port *dest_port = sparms.dest_port; 495 struct mlxsw_sp *mlxsw_sp = dest_port->mlxsw_sp; 496 u16 local_port = dest_port->local_port; 497 char mpat_pl[MLXSW_REG_MPAT_LEN]; 498 int pa_id = span_entry->id; 499 500 /* Create a new port analayzer entry for local_port. */ 501 mlxsw_reg_mpat_pack(mpat_pl, pa_id, local_port, true, 502 MLXSW_REG_MPAT_SPAN_TYPE_REMOTE_ETH_L3); 503 mlxsw_reg_mpat_pide_set(mpat_pl, sparms.policer_enable); 504 mlxsw_reg_mpat_pid_set(mpat_pl, sparms.policer_id); 505 mlxsw_reg_mpat_eth_rspan_pack(mpat_pl, sparms.vid); 506 mlxsw_reg_mpat_eth_rspan_l2_pack(mpat_pl, 507 MLXSW_REG_MPAT_ETH_RSPAN_VERSION_NO_HEADER, 508 sparms.dmac, !!sparms.vid); 509 mlxsw_reg_mpat_eth_rspan_l3_ipv4_pack(mpat_pl, 510 sparms.ttl, sparms.smac, 511 be32_to_cpu(sparms.saddr.addr4), 512 be32_to_cpu(sparms.daddr.addr4)); 513 514 return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(mpat), mpat_pl); 515 } 516 517 static void 518 mlxsw_sp_span_entry_gretap4_deconfigure(struct mlxsw_sp_span_entry *span_entry) 519 { 520 mlxsw_sp_span_entry_deconfigure_common(span_entry, 521 MLXSW_REG_MPAT_SPAN_TYPE_REMOTE_ETH_L3); 522 } 523 524 static const struct mlxsw_sp_span_entry_ops mlxsw_sp_span_entry_ops_gretap4 = { 525 .can_handle = netif_is_gretap, 526 .parms_set = mlxsw_sp_span_entry_gretap4_parms, 527 .configure = mlxsw_sp_span_entry_gretap4_configure, 528 .deconfigure = mlxsw_sp_span_entry_gretap4_deconfigure, 529 }; 530 #endif 531 532 #if IS_ENABLED(CONFIG_IPV6_GRE) 533 static struct net_device * 534 mlxsw_sp_span_gretap6_route(const struct net_device *to_dev, 535 struct in6_addr *saddrp, 536 struct in6_addr *daddrp) 537 { 538 struct ip6_tnl *t = netdev_priv(to_dev); 539 struct flowi6 fl6 = t->fl.u.ip6; 540 struct net_device *dev = NULL; 541 struct dst_entry *dst; 542 struct rt6_info *rt6; 543 544 /* We assume "dev" stays valid after dst is released. */ 545 ASSERT_RTNL(); 546 547 fl6.flowi6_mark = t->parms.fwmark; 548 if (!ip6_tnl_xmit_ctl(t, &fl6.saddr, &fl6.daddr)) 549 return NULL; 550 551 dst = ip6_route_output(t->net, NULL, &fl6); 552 if (!dst || dst->error) 553 goto out; 554 555 rt6 = dst_rt6_info(dst); 556 557 dev = dst->dev; 558 *saddrp = fl6.saddr; 559 *daddrp = rt6->rt6i_gateway; 560 561 out: 562 dst_release(dst); 563 return dev; 564 } 565 566 static int 567 mlxsw_sp_span_entry_gretap6_parms(struct mlxsw_sp *mlxsw_sp, 568 const struct net_device *to_dev, 569 struct mlxsw_sp_span_parms *sparmsp) 570 { 571 struct __ip6_tnl_parm tparm = mlxsw_sp_ipip_netdev_parms6(to_dev); 572 bool inherit_tos = tparm.flags & IP6_TNL_F_USE_ORIG_TCLASS; 573 union mlxsw_sp_l3addr saddr = { .addr6 = tparm.laddr }; 574 union mlxsw_sp_l3addr daddr = { .addr6 = tparm.raddr }; 575 bool inherit_ttl = !tparm.hop_limit; 576 union mlxsw_sp_l3addr gw = daddr; 577 struct net_device *l3edev; 578 579 if (!(to_dev->flags & IFF_UP) || 580 /* Reject tunnels with GRE keys, checksums, etc. */ 581 !ip_tunnel_flags_empty(tparm.i_flags) || 582 !ip_tunnel_flags_empty(tparm.o_flags) || 583 /* Require a fixed TTL and a TOS copied from the mirrored packet. */ 584 inherit_ttl || !inherit_tos || 585 /* A destination address may not be "any". */ 586 mlxsw_sp_l3addr_is_zero(daddr)) 587 return mlxsw_sp_span_entry_unoffloadable(sparmsp); 588 589 l3edev = mlxsw_sp_span_gretap6_route(to_dev, &saddr.addr6, &gw.addr6); 590 591 return mlxsw_sp_span_entry_tunnel_parms_common(l3edev, saddr, daddr, gw, 592 tparm.hop_limit, 593 AF_INET6, sparmsp); 594 } 595 596 static int 597 mlxsw_sp_span_entry_gretap6_configure(struct mlxsw_sp_span_entry *span_entry, 598 struct mlxsw_sp_span_parms sparms) 599 { 600 struct mlxsw_sp_port *dest_port = sparms.dest_port; 601 struct mlxsw_sp *mlxsw_sp = dest_port->mlxsw_sp; 602 u16 local_port = dest_port->local_port; 603 char mpat_pl[MLXSW_REG_MPAT_LEN]; 604 int pa_id = span_entry->id; 605 606 /* Create a new port analayzer entry for local_port. */ 607 mlxsw_reg_mpat_pack(mpat_pl, pa_id, local_port, true, 608 MLXSW_REG_MPAT_SPAN_TYPE_REMOTE_ETH_L3); 609 mlxsw_reg_mpat_pide_set(mpat_pl, sparms.policer_enable); 610 mlxsw_reg_mpat_pid_set(mpat_pl, sparms.policer_id); 611 mlxsw_reg_mpat_eth_rspan_pack(mpat_pl, sparms.vid); 612 mlxsw_reg_mpat_eth_rspan_l2_pack(mpat_pl, 613 MLXSW_REG_MPAT_ETH_RSPAN_VERSION_NO_HEADER, 614 sparms.dmac, !!sparms.vid); 615 mlxsw_reg_mpat_eth_rspan_l3_ipv6_pack(mpat_pl, sparms.ttl, sparms.smac, 616 sparms.saddr.addr6, 617 sparms.daddr.addr6); 618 619 return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(mpat), mpat_pl); 620 } 621 622 static void 623 mlxsw_sp_span_entry_gretap6_deconfigure(struct mlxsw_sp_span_entry *span_entry) 624 { 625 mlxsw_sp_span_entry_deconfigure_common(span_entry, 626 MLXSW_REG_MPAT_SPAN_TYPE_REMOTE_ETH_L3); 627 } 628 629 static const 630 struct mlxsw_sp_span_entry_ops mlxsw_sp_span_entry_ops_gretap6 = { 631 .can_handle = netif_is_ip6gretap, 632 .parms_set = mlxsw_sp_span_entry_gretap6_parms, 633 .configure = mlxsw_sp_span_entry_gretap6_configure, 634 .deconfigure = mlxsw_sp_span_entry_gretap6_deconfigure, 635 }; 636 #endif 637 638 static bool 639 mlxsw_sp_span_vlan_can_handle(const struct net_device *dev) 640 { 641 return is_vlan_dev(dev) && 642 mlxsw_sp_port_dev_check(vlan_dev_real_dev(dev)); 643 } 644 645 static int 646 mlxsw_sp_span_entry_vlan_parms(struct mlxsw_sp *mlxsw_sp, 647 const struct net_device *to_dev, 648 struct mlxsw_sp_span_parms *sparmsp) 649 { 650 struct net_device *real_dev; 651 u16 vid; 652 653 if (!(to_dev->flags & IFF_UP)) 654 return mlxsw_sp_span_entry_unoffloadable(sparmsp); 655 656 real_dev = mlxsw_sp_span_entry_vlan(to_dev, &vid); 657 sparmsp->dest_port = netdev_priv(real_dev); 658 sparmsp->vid = vid; 659 return 0; 660 } 661 662 static int 663 mlxsw_sp_span_entry_vlan_configure(struct mlxsw_sp_span_entry *span_entry, 664 struct mlxsw_sp_span_parms sparms) 665 { 666 struct mlxsw_sp_port *dest_port = sparms.dest_port; 667 struct mlxsw_sp *mlxsw_sp = dest_port->mlxsw_sp; 668 u16 local_port = dest_port->local_port; 669 char mpat_pl[MLXSW_REG_MPAT_LEN]; 670 int pa_id = span_entry->id; 671 672 mlxsw_reg_mpat_pack(mpat_pl, pa_id, local_port, true, 673 MLXSW_REG_MPAT_SPAN_TYPE_REMOTE_ETH); 674 mlxsw_reg_mpat_pide_set(mpat_pl, sparms.policer_enable); 675 mlxsw_reg_mpat_pid_set(mpat_pl, sparms.policer_id); 676 mlxsw_reg_mpat_eth_rspan_pack(mpat_pl, sparms.vid); 677 678 return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(mpat), mpat_pl); 679 } 680 681 static void 682 mlxsw_sp_span_entry_vlan_deconfigure(struct mlxsw_sp_span_entry *span_entry) 683 { 684 mlxsw_sp_span_entry_deconfigure_common(span_entry, 685 MLXSW_REG_MPAT_SPAN_TYPE_REMOTE_ETH); 686 } 687 688 static const 689 struct mlxsw_sp_span_entry_ops mlxsw_sp_span_entry_ops_vlan = { 690 .can_handle = mlxsw_sp_span_vlan_can_handle, 691 .parms_set = mlxsw_sp_span_entry_vlan_parms, 692 .configure = mlxsw_sp_span_entry_vlan_configure, 693 .deconfigure = mlxsw_sp_span_entry_vlan_deconfigure, 694 }; 695 696 static const 697 struct mlxsw_sp_span_entry_ops *mlxsw_sp1_span_entry_ops_arr[] = { 698 &mlxsw_sp1_span_entry_ops_cpu, 699 &mlxsw_sp_span_entry_ops_phys, 700 #if IS_ENABLED(CONFIG_NET_IPGRE) 701 &mlxsw_sp_span_entry_ops_gretap4, 702 #endif 703 #if IS_ENABLED(CONFIG_IPV6_GRE) 704 &mlxsw_sp_span_entry_ops_gretap6, 705 #endif 706 &mlxsw_sp_span_entry_ops_vlan, 707 }; 708 709 static bool mlxsw_sp2_span_cpu_can_handle(const struct net_device *dev) 710 { 711 return !dev; 712 } 713 714 static int mlxsw_sp2_span_entry_cpu_parms(struct mlxsw_sp *mlxsw_sp, 715 const struct net_device *to_dev, 716 struct mlxsw_sp_span_parms *sparmsp) 717 { 718 sparmsp->dest_port = mlxsw_sp->ports[MLXSW_PORT_CPU_PORT]; 719 return 0; 720 } 721 722 static int 723 mlxsw_sp2_span_entry_cpu_configure(struct mlxsw_sp_span_entry *span_entry, 724 struct mlxsw_sp_span_parms sparms) 725 { 726 /* Mirroring to the CPU port is like mirroring to any other physical 727 * port. Its local port is used instead of that of the physical port. 728 */ 729 return mlxsw_sp_span_entry_phys_configure(span_entry, sparms); 730 } 731 732 static void 733 mlxsw_sp2_span_entry_cpu_deconfigure(struct mlxsw_sp_span_entry *span_entry) 734 { 735 enum mlxsw_reg_mpat_span_type span_type; 736 737 span_type = MLXSW_REG_MPAT_SPAN_TYPE_LOCAL_ETH; 738 mlxsw_sp_span_entry_deconfigure_common(span_entry, span_type); 739 } 740 741 static const 742 struct mlxsw_sp_span_entry_ops mlxsw_sp2_span_entry_ops_cpu = { 743 .is_static = true, 744 .can_handle = mlxsw_sp2_span_cpu_can_handle, 745 .parms_set = mlxsw_sp2_span_entry_cpu_parms, 746 .configure = mlxsw_sp2_span_entry_cpu_configure, 747 .deconfigure = mlxsw_sp2_span_entry_cpu_deconfigure, 748 }; 749 750 static const 751 struct mlxsw_sp_span_entry_ops *mlxsw_sp2_span_entry_ops_arr[] = { 752 &mlxsw_sp2_span_entry_ops_cpu, 753 &mlxsw_sp_span_entry_ops_phys, 754 #if IS_ENABLED(CONFIG_NET_IPGRE) 755 &mlxsw_sp_span_entry_ops_gretap4, 756 #endif 757 #if IS_ENABLED(CONFIG_IPV6_GRE) 758 &mlxsw_sp_span_entry_ops_gretap6, 759 #endif 760 &mlxsw_sp_span_entry_ops_vlan, 761 }; 762 763 static int 764 mlxsw_sp_span_entry_nop_parms(struct mlxsw_sp *mlxsw_sp, 765 const struct net_device *to_dev, 766 struct mlxsw_sp_span_parms *sparmsp) 767 { 768 return mlxsw_sp_span_entry_unoffloadable(sparmsp); 769 } 770 771 static int 772 mlxsw_sp_span_entry_nop_configure(struct mlxsw_sp_span_entry *span_entry, 773 struct mlxsw_sp_span_parms sparms) 774 { 775 return 0; 776 } 777 778 static void 779 mlxsw_sp_span_entry_nop_deconfigure(struct mlxsw_sp_span_entry *span_entry) 780 { 781 } 782 783 static const struct mlxsw_sp_span_entry_ops mlxsw_sp_span_entry_ops_nop = { 784 .parms_set = mlxsw_sp_span_entry_nop_parms, 785 .configure = mlxsw_sp_span_entry_nop_configure, 786 .deconfigure = mlxsw_sp_span_entry_nop_deconfigure, 787 }; 788 789 static void 790 mlxsw_sp_span_entry_configure(struct mlxsw_sp *mlxsw_sp, 791 struct mlxsw_sp_span_entry *span_entry, 792 struct mlxsw_sp_span_parms sparms) 793 { 794 int err; 795 796 if (!sparms.dest_port) 797 goto set_parms; 798 799 if (sparms.dest_port->mlxsw_sp != mlxsw_sp) { 800 dev_err(mlxsw_sp->bus_info->dev, 801 "Cannot mirror to a port which belongs to a different mlxsw instance\n"); 802 sparms.dest_port = NULL; 803 goto set_parms; 804 } 805 806 err = span_entry->ops->configure(span_entry, sparms); 807 if (err) { 808 dev_err(mlxsw_sp->bus_info->dev, "Failed to offload mirror\n"); 809 sparms.dest_port = NULL; 810 goto set_parms; 811 } 812 813 set_parms: 814 span_entry->parms = sparms; 815 } 816 817 static void 818 mlxsw_sp_span_entry_deconfigure(struct mlxsw_sp_span_entry *span_entry) 819 { 820 if (span_entry->parms.dest_port) 821 span_entry->ops->deconfigure(span_entry); 822 } 823 824 static int mlxsw_sp_span_policer_id_base_set(struct mlxsw_sp_span *span, 825 u16 policer_id) 826 { 827 struct mlxsw_sp *mlxsw_sp = span->mlxsw_sp; 828 u16 policer_id_base; 829 int err; 830 831 /* Policers set on SPAN agents must be in the range of 832 * `policer_id_base .. policer_id_base + max_span_agents - 1`. If the 833 * base is set and the new policer is not within the range, then we 834 * must error out. 835 */ 836 if (refcount_read(&span->policer_id_base_ref_count)) { 837 if (policer_id < span->policer_id_base || 838 policer_id >= span->policer_id_base + span->entries_count) 839 return -EINVAL; 840 841 refcount_inc(&span->policer_id_base_ref_count); 842 return 0; 843 } 844 845 /* Base must be even. */ 846 policer_id_base = policer_id % 2 == 0 ? policer_id : policer_id - 1; 847 err = mlxsw_sp->span_ops->policer_id_base_set(mlxsw_sp, 848 policer_id_base); 849 if (err) 850 return err; 851 852 span->policer_id_base = policer_id_base; 853 refcount_set(&span->policer_id_base_ref_count, 1); 854 855 return 0; 856 } 857 858 static void mlxsw_sp_span_policer_id_base_unset(struct mlxsw_sp_span *span) 859 { 860 if (refcount_dec_and_test(&span->policer_id_base_ref_count)) 861 span->policer_id_base = 0; 862 } 863 864 static struct mlxsw_sp_span_entry * 865 mlxsw_sp_span_entry_create(struct mlxsw_sp *mlxsw_sp, 866 const struct net_device *to_dev, 867 const struct mlxsw_sp_span_entry_ops *ops, 868 struct mlxsw_sp_span_parms sparms) 869 { 870 struct mlxsw_sp_span_entry *span_entry = NULL; 871 int i; 872 873 /* find a free entry to use */ 874 for (i = 0; i < mlxsw_sp->span->entries_count; i++) { 875 if (!refcount_read(&mlxsw_sp->span->entries[i].ref_count)) { 876 span_entry = &mlxsw_sp->span->entries[i]; 877 break; 878 } 879 } 880 if (!span_entry) 881 return NULL; 882 883 if (sparms.policer_enable) { 884 int err; 885 886 err = mlxsw_sp_span_policer_id_base_set(mlxsw_sp->span, 887 sparms.policer_id); 888 if (err) 889 return NULL; 890 } 891 892 atomic_inc(&mlxsw_sp->span->active_entries_count); 893 span_entry->ops = ops; 894 refcount_set(&span_entry->ref_count, 1); 895 span_entry->to_dev = to_dev; 896 mlxsw_sp_span_entry_configure(mlxsw_sp, span_entry, sparms); 897 898 return span_entry; 899 } 900 901 static void mlxsw_sp_span_entry_destroy(struct mlxsw_sp *mlxsw_sp, 902 struct mlxsw_sp_span_entry *span_entry) 903 { 904 mlxsw_sp_span_entry_deconfigure(span_entry); 905 atomic_dec(&mlxsw_sp->span->active_entries_count); 906 if (span_entry->parms.policer_enable) 907 mlxsw_sp_span_policer_id_base_unset(mlxsw_sp->span); 908 } 909 910 struct mlxsw_sp_span_entry * 911 mlxsw_sp_span_entry_find_by_port(struct mlxsw_sp *mlxsw_sp, 912 const struct net_device *to_dev) 913 { 914 int i; 915 916 for (i = 0; i < mlxsw_sp->span->entries_count; i++) { 917 struct mlxsw_sp_span_entry *curr = &mlxsw_sp->span->entries[i]; 918 919 if (refcount_read(&curr->ref_count) && curr->to_dev == to_dev) 920 return curr; 921 } 922 return NULL; 923 } 924 925 void mlxsw_sp_span_entry_invalidate(struct mlxsw_sp *mlxsw_sp, 926 struct mlxsw_sp_span_entry *span_entry) 927 { 928 mlxsw_sp_span_entry_deconfigure(span_entry); 929 span_entry->ops = &mlxsw_sp_span_entry_ops_nop; 930 } 931 932 static struct mlxsw_sp_span_entry * 933 mlxsw_sp_span_entry_find_by_id(struct mlxsw_sp *mlxsw_sp, int span_id) 934 { 935 int i; 936 937 for (i = 0; i < mlxsw_sp->span->entries_count; i++) { 938 struct mlxsw_sp_span_entry *curr = &mlxsw_sp->span->entries[i]; 939 940 if (refcount_read(&curr->ref_count) && curr->id == span_id) 941 return curr; 942 } 943 return NULL; 944 } 945 946 static struct mlxsw_sp_span_entry * 947 mlxsw_sp_span_entry_find_by_parms(struct mlxsw_sp *mlxsw_sp, 948 const struct net_device *to_dev, 949 const struct mlxsw_sp_span_parms *sparms) 950 { 951 int i; 952 953 for (i = 0; i < mlxsw_sp->span->entries_count; i++) { 954 struct mlxsw_sp_span_entry *curr = &mlxsw_sp->span->entries[i]; 955 956 if (refcount_read(&curr->ref_count) && curr->to_dev == to_dev && 957 curr->parms.policer_enable == sparms->policer_enable && 958 curr->parms.policer_id == sparms->policer_id && 959 curr->parms.session_id == sparms->session_id) 960 return curr; 961 } 962 return NULL; 963 } 964 965 static struct mlxsw_sp_span_entry * 966 mlxsw_sp_span_entry_get(struct mlxsw_sp *mlxsw_sp, 967 const struct net_device *to_dev, 968 const struct mlxsw_sp_span_entry_ops *ops, 969 struct mlxsw_sp_span_parms sparms) 970 { 971 struct mlxsw_sp_span_entry *span_entry; 972 973 span_entry = mlxsw_sp_span_entry_find_by_parms(mlxsw_sp, to_dev, 974 &sparms); 975 if (span_entry) { 976 /* Already exists, just take a reference */ 977 refcount_inc(&span_entry->ref_count); 978 return span_entry; 979 } 980 981 return mlxsw_sp_span_entry_create(mlxsw_sp, to_dev, ops, sparms); 982 } 983 984 static int mlxsw_sp_span_entry_put(struct mlxsw_sp *mlxsw_sp, 985 struct mlxsw_sp_span_entry *span_entry) 986 { 987 if (refcount_dec_and_test(&span_entry->ref_count)) 988 mlxsw_sp_span_entry_destroy(mlxsw_sp, span_entry); 989 return 0; 990 } 991 992 static int mlxsw_sp_span_port_buffer_update(struct mlxsw_sp_port *mlxsw_sp_port, bool enable) 993 { 994 struct mlxsw_sp_hdroom hdroom; 995 996 hdroom = *mlxsw_sp_port->hdroom; 997 hdroom.int_buf.enable = enable; 998 mlxsw_sp_hdroom_bufs_reset_sizes(mlxsw_sp_port, &hdroom); 999 1000 return mlxsw_sp_hdroom_configure(mlxsw_sp_port, &hdroom); 1001 } 1002 1003 static int 1004 mlxsw_sp_span_port_buffer_enable(struct mlxsw_sp_port *mlxsw_sp_port) 1005 { 1006 return mlxsw_sp_span_port_buffer_update(mlxsw_sp_port, true); 1007 } 1008 1009 static void mlxsw_sp_span_port_buffer_disable(struct mlxsw_sp_port *mlxsw_sp_port) 1010 { 1011 mlxsw_sp_span_port_buffer_update(mlxsw_sp_port, false); 1012 } 1013 1014 static struct mlxsw_sp_span_analyzed_port * 1015 mlxsw_sp_span_analyzed_port_find(struct mlxsw_sp_span *span, u16 local_port, 1016 bool ingress) 1017 { 1018 struct mlxsw_sp_span_analyzed_port *analyzed_port; 1019 1020 list_for_each_entry(analyzed_port, &span->analyzed_ports_list, list) { 1021 if (analyzed_port->local_port == local_port && 1022 analyzed_port->ingress == ingress) 1023 return analyzed_port; 1024 } 1025 1026 return NULL; 1027 } 1028 1029 static const struct mlxsw_sp_span_entry_ops * 1030 mlxsw_sp_span_entry_ops(struct mlxsw_sp *mlxsw_sp, 1031 const struct net_device *to_dev) 1032 { 1033 struct mlxsw_sp_span *span = mlxsw_sp->span; 1034 size_t i; 1035 1036 for (i = 0; i < span->span_entry_ops_arr_size; ++i) 1037 if (span->span_entry_ops_arr[i]->can_handle(to_dev)) 1038 return span->span_entry_ops_arr[i]; 1039 1040 return NULL; 1041 } 1042 1043 static void mlxsw_sp_span_respin_work(struct work_struct *work) 1044 { 1045 struct mlxsw_sp_span *span; 1046 struct mlxsw_sp *mlxsw_sp; 1047 int i, err; 1048 1049 span = container_of(work, struct mlxsw_sp_span, work); 1050 mlxsw_sp = span->mlxsw_sp; 1051 1052 rtnl_lock(); 1053 for (i = 0; i < mlxsw_sp->span->entries_count; i++) { 1054 struct mlxsw_sp_span_entry *curr = &mlxsw_sp->span->entries[i]; 1055 struct mlxsw_sp_span_parms sparms = {NULL}; 1056 1057 if (!refcount_read(&curr->ref_count)) 1058 continue; 1059 1060 if (curr->ops->is_static) 1061 continue; 1062 1063 err = curr->ops->parms_set(mlxsw_sp, curr->to_dev, &sparms); 1064 if (err) 1065 continue; 1066 1067 if (memcmp(&sparms, &curr->parms, sizeof(sparms))) { 1068 mlxsw_sp_span_entry_deconfigure(curr); 1069 mlxsw_sp_span_entry_configure(mlxsw_sp, curr, sparms); 1070 } 1071 } 1072 rtnl_unlock(); 1073 } 1074 1075 void mlxsw_sp_span_respin(struct mlxsw_sp *mlxsw_sp) 1076 { 1077 if (atomic_read(&mlxsw_sp->span->active_entries_count) == 0) 1078 return; 1079 mlxsw_core_schedule_work(&mlxsw_sp->span->work); 1080 } 1081 1082 int mlxsw_sp_span_agent_get(struct mlxsw_sp *mlxsw_sp, int *p_span_id, 1083 const struct mlxsw_sp_span_agent_parms *parms) 1084 { 1085 const struct net_device *to_dev = parms->to_dev; 1086 const struct mlxsw_sp_span_entry_ops *ops; 1087 struct mlxsw_sp_span_entry *span_entry; 1088 struct mlxsw_sp_span_parms sparms; 1089 int err; 1090 1091 ASSERT_RTNL(); 1092 1093 ops = mlxsw_sp_span_entry_ops(mlxsw_sp, to_dev); 1094 if (!ops) { 1095 dev_err(mlxsw_sp->bus_info->dev, "Cannot mirror to requested destination\n"); 1096 return -EOPNOTSUPP; 1097 } 1098 1099 memset(&sparms, 0, sizeof(sparms)); 1100 err = ops->parms_set(mlxsw_sp, to_dev, &sparms); 1101 if (err) 1102 return err; 1103 1104 sparms.policer_id = parms->policer_id; 1105 sparms.policer_enable = parms->policer_enable; 1106 sparms.session_id = parms->session_id; 1107 span_entry = mlxsw_sp_span_entry_get(mlxsw_sp, to_dev, ops, sparms); 1108 if (!span_entry) 1109 return -ENOBUFS; 1110 1111 *p_span_id = span_entry->id; 1112 1113 return 0; 1114 } 1115 1116 void mlxsw_sp_span_agent_put(struct mlxsw_sp *mlxsw_sp, int span_id) 1117 { 1118 struct mlxsw_sp_span_entry *span_entry; 1119 1120 ASSERT_RTNL(); 1121 1122 span_entry = mlxsw_sp_span_entry_find_by_id(mlxsw_sp, span_id); 1123 if (WARN_ON_ONCE(!span_entry)) 1124 return; 1125 1126 mlxsw_sp_span_entry_put(mlxsw_sp, span_entry); 1127 } 1128 1129 static struct mlxsw_sp_span_analyzed_port * 1130 mlxsw_sp_span_analyzed_port_create(struct mlxsw_sp_span *span, 1131 struct mlxsw_sp_port *mlxsw_sp_port, 1132 bool ingress) 1133 { 1134 struct mlxsw_sp_span_analyzed_port *analyzed_port; 1135 int err; 1136 1137 analyzed_port = kzalloc_obj(*analyzed_port); 1138 if (!analyzed_port) 1139 return ERR_PTR(-ENOMEM); 1140 1141 refcount_set(&analyzed_port->ref_count, 1); 1142 analyzed_port->local_port = mlxsw_sp_port->local_port; 1143 analyzed_port->ingress = ingress; 1144 list_add_tail(&analyzed_port->list, &span->analyzed_ports_list); 1145 1146 /* An egress mirror buffer should be allocated on the egress port which 1147 * does the mirroring. 1148 */ 1149 if (!ingress) { 1150 err = mlxsw_sp_span_port_buffer_enable(mlxsw_sp_port); 1151 if (err) 1152 goto err_buffer_update; 1153 } 1154 1155 return analyzed_port; 1156 1157 err_buffer_update: 1158 list_del(&analyzed_port->list); 1159 kfree(analyzed_port); 1160 return ERR_PTR(err); 1161 } 1162 1163 static void 1164 mlxsw_sp_span_analyzed_port_destroy(struct mlxsw_sp_port *mlxsw_sp_port, 1165 struct mlxsw_sp_span_analyzed_port * 1166 analyzed_port) 1167 { 1168 /* Remove egress mirror buffer now that port is no longer analyzed 1169 * at egress. 1170 */ 1171 if (!analyzed_port->ingress) 1172 mlxsw_sp_span_port_buffer_disable(mlxsw_sp_port); 1173 1174 list_del(&analyzed_port->list); 1175 kfree(analyzed_port); 1176 } 1177 1178 int mlxsw_sp_span_analyzed_port_get(struct mlxsw_sp_port *mlxsw_sp_port, 1179 bool ingress) 1180 { 1181 struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; 1182 struct mlxsw_sp_span_analyzed_port *analyzed_port; 1183 u16 local_port = mlxsw_sp_port->local_port; 1184 int err = 0; 1185 1186 mutex_lock(&mlxsw_sp->span->analyzed_ports_lock); 1187 1188 analyzed_port = mlxsw_sp_span_analyzed_port_find(mlxsw_sp->span, 1189 local_port, ingress); 1190 if (analyzed_port) { 1191 refcount_inc(&analyzed_port->ref_count); 1192 goto out_unlock; 1193 } 1194 1195 analyzed_port = mlxsw_sp_span_analyzed_port_create(mlxsw_sp->span, 1196 mlxsw_sp_port, 1197 ingress); 1198 if (IS_ERR(analyzed_port)) 1199 err = PTR_ERR(analyzed_port); 1200 1201 out_unlock: 1202 mutex_unlock(&mlxsw_sp->span->analyzed_ports_lock); 1203 return err; 1204 } 1205 1206 void mlxsw_sp_span_analyzed_port_put(struct mlxsw_sp_port *mlxsw_sp_port, 1207 bool ingress) 1208 { 1209 struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; 1210 struct mlxsw_sp_span_analyzed_port *analyzed_port; 1211 u16 local_port = mlxsw_sp_port->local_port; 1212 1213 mutex_lock(&mlxsw_sp->span->analyzed_ports_lock); 1214 1215 analyzed_port = mlxsw_sp_span_analyzed_port_find(mlxsw_sp->span, 1216 local_port, ingress); 1217 if (WARN_ON_ONCE(!analyzed_port)) 1218 goto out_unlock; 1219 1220 if (!refcount_dec_and_test(&analyzed_port->ref_count)) 1221 goto out_unlock; 1222 1223 mlxsw_sp_span_analyzed_port_destroy(mlxsw_sp_port, analyzed_port); 1224 1225 out_unlock: 1226 mutex_unlock(&mlxsw_sp->span->analyzed_ports_lock); 1227 } 1228 1229 static int 1230 __mlxsw_sp_span_trigger_port_bind(struct mlxsw_sp_span *span, 1231 struct mlxsw_sp_span_trigger_entry * 1232 trigger_entry, bool enable) 1233 { 1234 char mpar_pl[MLXSW_REG_MPAR_LEN]; 1235 enum mlxsw_reg_mpar_i_e i_e; 1236 1237 switch (trigger_entry->trigger) { 1238 case MLXSW_SP_SPAN_TRIGGER_INGRESS: 1239 i_e = MLXSW_REG_MPAR_TYPE_INGRESS; 1240 break; 1241 case MLXSW_SP_SPAN_TRIGGER_EGRESS: 1242 i_e = MLXSW_REG_MPAR_TYPE_EGRESS; 1243 break; 1244 default: 1245 WARN_ON_ONCE(1); 1246 return -EINVAL; 1247 } 1248 1249 if (trigger_entry->parms.probability_rate > MLXSW_REG_MPAR_RATE_MAX) 1250 return -EINVAL; 1251 1252 mlxsw_reg_mpar_pack(mpar_pl, trigger_entry->local_port, i_e, enable, 1253 trigger_entry->parms.span_id, 1254 trigger_entry->parms.probability_rate); 1255 return mlxsw_reg_write(span->mlxsw_sp->core, MLXSW_REG(mpar), mpar_pl); 1256 } 1257 1258 static int 1259 mlxsw_sp_span_trigger_port_bind(struct mlxsw_sp_span_trigger_entry * 1260 trigger_entry) 1261 { 1262 return __mlxsw_sp_span_trigger_port_bind(trigger_entry->span, 1263 trigger_entry, true); 1264 } 1265 1266 static void 1267 mlxsw_sp_span_trigger_port_unbind(struct mlxsw_sp_span_trigger_entry * 1268 trigger_entry) 1269 { 1270 __mlxsw_sp_span_trigger_port_bind(trigger_entry->span, trigger_entry, 1271 false); 1272 } 1273 1274 static bool 1275 mlxsw_sp_span_trigger_port_matches(struct mlxsw_sp_span_trigger_entry * 1276 trigger_entry, 1277 enum mlxsw_sp_span_trigger trigger, 1278 struct mlxsw_sp_port *mlxsw_sp_port) 1279 { 1280 return trigger_entry->trigger == trigger && 1281 trigger_entry->local_port == mlxsw_sp_port->local_port; 1282 } 1283 1284 static int 1285 mlxsw_sp_span_trigger_port_enable(struct mlxsw_sp_span_trigger_entry * 1286 trigger_entry, 1287 struct mlxsw_sp_port *mlxsw_sp_port, u8 tc) 1288 { 1289 /* Port trigger are enabled during binding. */ 1290 return 0; 1291 } 1292 1293 static void 1294 mlxsw_sp_span_trigger_port_disable(struct mlxsw_sp_span_trigger_entry * 1295 trigger_entry, 1296 struct mlxsw_sp_port *mlxsw_sp_port, u8 tc) 1297 { 1298 } 1299 1300 static const struct mlxsw_sp_span_trigger_ops 1301 mlxsw_sp_span_trigger_port_ops = { 1302 .bind = mlxsw_sp_span_trigger_port_bind, 1303 .unbind = mlxsw_sp_span_trigger_port_unbind, 1304 .matches = mlxsw_sp_span_trigger_port_matches, 1305 .enable = mlxsw_sp_span_trigger_port_enable, 1306 .disable = mlxsw_sp_span_trigger_port_disable, 1307 }; 1308 1309 static int 1310 mlxsw_sp1_span_trigger_global_bind(struct mlxsw_sp_span_trigger_entry * 1311 trigger_entry) 1312 { 1313 return -EOPNOTSUPP; 1314 } 1315 1316 static void 1317 mlxsw_sp1_span_trigger_global_unbind(struct mlxsw_sp_span_trigger_entry * 1318 trigger_entry) 1319 { 1320 } 1321 1322 static bool 1323 mlxsw_sp1_span_trigger_global_matches(struct mlxsw_sp_span_trigger_entry * 1324 trigger_entry, 1325 enum mlxsw_sp_span_trigger trigger, 1326 struct mlxsw_sp_port *mlxsw_sp_port) 1327 { 1328 WARN_ON_ONCE(1); 1329 return false; 1330 } 1331 1332 static int 1333 mlxsw_sp1_span_trigger_global_enable(struct mlxsw_sp_span_trigger_entry * 1334 trigger_entry, 1335 struct mlxsw_sp_port *mlxsw_sp_port, 1336 u8 tc) 1337 { 1338 return -EOPNOTSUPP; 1339 } 1340 1341 static void 1342 mlxsw_sp1_span_trigger_global_disable(struct mlxsw_sp_span_trigger_entry * 1343 trigger_entry, 1344 struct mlxsw_sp_port *mlxsw_sp_port, 1345 u8 tc) 1346 { 1347 } 1348 1349 static const struct mlxsw_sp_span_trigger_ops 1350 mlxsw_sp1_span_trigger_global_ops = { 1351 .bind = mlxsw_sp1_span_trigger_global_bind, 1352 .unbind = mlxsw_sp1_span_trigger_global_unbind, 1353 .matches = mlxsw_sp1_span_trigger_global_matches, 1354 .enable = mlxsw_sp1_span_trigger_global_enable, 1355 .disable = mlxsw_sp1_span_trigger_global_disable, 1356 }; 1357 1358 static const struct mlxsw_sp_span_trigger_ops * 1359 mlxsw_sp1_span_trigger_ops_arr[] = { 1360 [MLXSW_SP_SPAN_TRIGGER_TYPE_PORT] = &mlxsw_sp_span_trigger_port_ops, 1361 [MLXSW_SP_SPAN_TRIGGER_TYPE_GLOBAL] = 1362 &mlxsw_sp1_span_trigger_global_ops, 1363 }; 1364 1365 static int 1366 mlxsw_sp2_span_trigger_global_bind(struct mlxsw_sp_span_trigger_entry * 1367 trigger_entry) 1368 { 1369 struct mlxsw_sp *mlxsw_sp = trigger_entry->span->mlxsw_sp; 1370 enum mlxsw_reg_mpagr_trigger trigger; 1371 char mpagr_pl[MLXSW_REG_MPAGR_LEN]; 1372 1373 switch (trigger_entry->trigger) { 1374 case MLXSW_SP_SPAN_TRIGGER_TAIL_DROP: 1375 trigger = MLXSW_REG_MPAGR_TRIGGER_INGRESS_SHARED_BUFFER; 1376 break; 1377 case MLXSW_SP_SPAN_TRIGGER_EARLY_DROP: 1378 trigger = MLXSW_REG_MPAGR_TRIGGER_INGRESS_WRED; 1379 break; 1380 case MLXSW_SP_SPAN_TRIGGER_ECN: 1381 trigger = MLXSW_REG_MPAGR_TRIGGER_EGRESS_ECN; 1382 break; 1383 default: 1384 WARN_ON_ONCE(1); 1385 return -EINVAL; 1386 } 1387 1388 if (trigger_entry->parms.probability_rate > MLXSW_REG_MPAGR_RATE_MAX) 1389 return -EINVAL; 1390 1391 mlxsw_reg_mpagr_pack(mpagr_pl, trigger, trigger_entry->parms.span_id, 1392 trigger_entry->parms.probability_rate); 1393 return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(mpagr), mpagr_pl); 1394 } 1395 1396 static void 1397 mlxsw_sp2_span_trigger_global_unbind(struct mlxsw_sp_span_trigger_entry * 1398 trigger_entry) 1399 { 1400 /* There is no unbinding for global triggers. The trigger should be 1401 * disabled on all ports by now. 1402 */ 1403 } 1404 1405 static bool 1406 mlxsw_sp2_span_trigger_global_matches(struct mlxsw_sp_span_trigger_entry * 1407 trigger_entry, 1408 enum mlxsw_sp_span_trigger trigger, 1409 struct mlxsw_sp_port *mlxsw_sp_port) 1410 { 1411 return trigger_entry->trigger == trigger; 1412 } 1413 1414 static int 1415 __mlxsw_sp2_span_trigger_global_enable(struct mlxsw_sp_span_trigger_entry * 1416 trigger_entry, 1417 struct mlxsw_sp_port *mlxsw_sp_port, 1418 u8 tc, bool enable) 1419 { 1420 struct mlxsw_sp *mlxsw_sp = trigger_entry->span->mlxsw_sp; 1421 char momte_pl[MLXSW_REG_MOMTE_LEN]; 1422 enum mlxsw_reg_momte_type type; 1423 int err; 1424 1425 switch (trigger_entry->trigger) { 1426 case MLXSW_SP_SPAN_TRIGGER_TAIL_DROP: 1427 type = MLXSW_REG_MOMTE_TYPE_SHARED_BUFFER_TCLASS; 1428 break; 1429 case MLXSW_SP_SPAN_TRIGGER_EARLY_DROP: 1430 type = MLXSW_REG_MOMTE_TYPE_WRED; 1431 break; 1432 case MLXSW_SP_SPAN_TRIGGER_ECN: 1433 type = MLXSW_REG_MOMTE_TYPE_ECN; 1434 break; 1435 default: 1436 WARN_ON_ONCE(1); 1437 return -EINVAL; 1438 } 1439 1440 /* Query existing configuration in order to only change the state of 1441 * the specified traffic class. 1442 */ 1443 mlxsw_reg_momte_pack(momte_pl, mlxsw_sp_port->local_port, type); 1444 err = mlxsw_reg_query(mlxsw_sp->core, MLXSW_REG(momte), momte_pl); 1445 if (err) 1446 return err; 1447 1448 mlxsw_reg_momte_tclass_en_set(momte_pl, tc, enable); 1449 return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(momte), momte_pl); 1450 } 1451 1452 static int 1453 mlxsw_sp2_span_trigger_global_enable(struct mlxsw_sp_span_trigger_entry * 1454 trigger_entry, 1455 struct mlxsw_sp_port *mlxsw_sp_port, 1456 u8 tc) 1457 { 1458 return __mlxsw_sp2_span_trigger_global_enable(trigger_entry, 1459 mlxsw_sp_port, tc, true); 1460 } 1461 1462 static void 1463 mlxsw_sp2_span_trigger_global_disable(struct mlxsw_sp_span_trigger_entry * 1464 trigger_entry, 1465 struct mlxsw_sp_port *mlxsw_sp_port, 1466 u8 tc) 1467 { 1468 __mlxsw_sp2_span_trigger_global_enable(trigger_entry, mlxsw_sp_port, tc, 1469 false); 1470 } 1471 1472 static const struct mlxsw_sp_span_trigger_ops 1473 mlxsw_sp2_span_trigger_global_ops = { 1474 .bind = mlxsw_sp2_span_trigger_global_bind, 1475 .unbind = mlxsw_sp2_span_trigger_global_unbind, 1476 .matches = mlxsw_sp2_span_trigger_global_matches, 1477 .enable = mlxsw_sp2_span_trigger_global_enable, 1478 .disable = mlxsw_sp2_span_trigger_global_disable, 1479 }; 1480 1481 static const struct mlxsw_sp_span_trigger_ops * 1482 mlxsw_sp2_span_trigger_ops_arr[] = { 1483 [MLXSW_SP_SPAN_TRIGGER_TYPE_PORT] = &mlxsw_sp_span_trigger_port_ops, 1484 [MLXSW_SP_SPAN_TRIGGER_TYPE_GLOBAL] = 1485 &mlxsw_sp2_span_trigger_global_ops, 1486 }; 1487 1488 static void 1489 mlxsw_sp_span_trigger_ops_set(struct mlxsw_sp_span_trigger_entry *trigger_entry) 1490 { 1491 struct mlxsw_sp_span *span = trigger_entry->span; 1492 enum mlxsw_sp_span_trigger_type type; 1493 1494 switch (trigger_entry->trigger) { 1495 case MLXSW_SP_SPAN_TRIGGER_INGRESS: 1496 case MLXSW_SP_SPAN_TRIGGER_EGRESS: 1497 type = MLXSW_SP_SPAN_TRIGGER_TYPE_PORT; 1498 break; 1499 case MLXSW_SP_SPAN_TRIGGER_TAIL_DROP: 1500 case MLXSW_SP_SPAN_TRIGGER_EARLY_DROP: 1501 case MLXSW_SP_SPAN_TRIGGER_ECN: 1502 type = MLXSW_SP_SPAN_TRIGGER_TYPE_GLOBAL; 1503 break; 1504 default: 1505 WARN_ON_ONCE(1); 1506 return; 1507 } 1508 1509 trigger_entry->ops = span->span_trigger_ops_arr[type]; 1510 } 1511 1512 static struct mlxsw_sp_span_trigger_entry * 1513 mlxsw_sp_span_trigger_entry_create(struct mlxsw_sp_span *span, 1514 enum mlxsw_sp_span_trigger trigger, 1515 struct mlxsw_sp_port *mlxsw_sp_port, 1516 const struct mlxsw_sp_span_trigger_parms 1517 *parms) 1518 { 1519 struct mlxsw_sp_span_trigger_entry *trigger_entry; 1520 int err; 1521 1522 trigger_entry = kzalloc_obj(*trigger_entry); 1523 if (!trigger_entry) 1524 return ERR_PTR(-ENOMEM); 1525 1526 refcount_set(&trigger_entry->ref_count, 1); 1527 trigger_entry->local_port = mlxsw_sp_port ? mlxsw_sp_port->local_port : 1528 0; 1529 trigger_entry->trigger = trigger; 1530 memcpy(&trigger_entry->parms, parms, sizeof(trigger_entry->parms)); 1531 trigger_entry->span = span; 1532 mlxsw_sp_span_trigger_ops_set(trigger_entry); 1533 list_add_tail(&trigger_entry->list, &span->trigger_entries_list); 1534 1535 err = trigger_entry->ops->bind(trigger_entry); 1536 if (err) 1537 goto err_trigger_entry_bind; 1538 1539 return trigger_entry; 1540 1541 err_trigger_entry_bind: 1542 list_del(&trigger_entry->list); 1543 kfree(trigger_entry); 1544 return ERR_PTR(err); 1545 } 1546 1547 static void 1548 mlxsw_sp_span_trigger_entry_destroy(struct mlxsw_sp_span *span, 1549 struct mlxsw_sp_span_trigger_entry * 1550 trigger_entry) 1551 { 1552 trigger_entry->ops->unbind(trigger_entry); 1553 list_del(&trigger_entry->list); 1554 kfree(trigger_entry); 1555 } 1556 1557 static struct mlxsw_sp_span_trigger_entry * 1558 mlxsw_sp_span_trigger_entry_find(struct mlxsw_sp_span *span, 1559 enum mlxsw_sp_span_trigger trigger, 1560 struct mlxsw_sp_port *mlxsw_sp_port) 1561 { 1562 struct mlxsw_sp_span_trigger_entry *trigger_entry; 1563 1564 list_for_each_entry(trigger_entry, &span->trigger_entries_list, list) { 1565 if (trigger_entry->ops->matches(trigger_entry, trigger, 1566 mlxsw_sp_port)) 1567 return trigger_entry; 1568 } 1569 1570 return NULL; 1571 } 1572 1573 int mlxsw_sp_span_agent_bind(struct mlxsw_sp *mlxsw_sp, 1574 enum mlxsw_sp_span_trigger trigger, 1575 struct mlxsw_sp_port *mlxsw_sp_port, 1576 const struct mlxsw_sp_span_trigger_parms *parms) 1577 { 1578 struct mlxsw_sp_span_trigger_entry *trigger_entry; 1579 int err = 0; 1580 1581 ASSERT_RTNL(); 1582 1583 if (!mlxsw_sp_span_entry_find_by_id(mlxsw_sp, parms->span_id)) 1584 return -EINVAL; 1585 1586 trigger_entry = mlxsw_sp_span_trigger_entry_find(mlxsw_sp->span, 1587 trigger, 1588 mlxsw_sp_port); 1589 if (trigger_entry) { 1590 if (trigger_entry->parms.span_id != parms->span_id || 1591 trigger_entry->parms.probability_rate != 1592 parms->probability_rate) 1593 return -EINVAL; 1594 refcount_inc(&trigger_entry->ref_count); 1595 goto out; 1596 } 1597 1598 trigger_entry = mlxsw_sp_span_trigger_entry_create(mlxsw_sp->span, 1599 trigger, 1600 mlxsw_sp_port, 1601 parms); 1602 if (IS_ERR(trigger_entry)) 1603 err = PTR_ERR(trigger_entry); 1604 1605 out: 1606 return err; 1607 } 1608 1609 void mlxsw_sp_span_agent_unbind(struct mlxsw_sp *mlxsw_sp, 1610 enum mlxsw_sp_span_trigger trigger, 1611 struct mlxsw_sp_port *mlxsw_sp_port, 1612 const struct mlxsw_sp_span_trigger_parms *parms) 1613 { 1614 struct mlxsw_sp_span_trigger_entry *trigger_entry; 1615 1616 ASSERT_RTNL(); 1617 1618 if (WARN_ON_ONCE(!mlxsw_sp_span_entry_find_by_id(mlxsw_sp, 1619 parms->span_id))) 1620 return; 1621 1622 trigger_entry = mlxsw_sp_span_trigger_entry_find(mlxsw_sp->span, 1623 trigger, 1624 mlxsw_sp_port); 1625 if (WARN_ON_ONCE(!trigger_entry)) 1626 return; 1627 1628 if (!refcount_dec_and_test(&trigger_entry->ref_count)) 1629 return; 1630 1631 mlxsw_sp_span_trigger_entry_destroy(mlxsw_sp->span, trigger_entry); 1632 } 1633 1634 int mlxsw_sp_span_trigger_enable(struct mlxsw_sp_port *mlxsw_sp_port, 1635 enum mlxsw_sp_span_trigger trigger, u8 tc) 1636 { 1637 struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; 1638 struct mlxsw_sp_span_trigger_entry *trigger_entry; 1639 1640 ASSERT_RTNL(); 1641 1642 trigger_entry = mlxsw_sp_span_trigger_entry_find(mlxsw_sp->span, 1643 trigger, 1644 mlxsw_sp_port); 1645 if (WARN_ON_ONCE(!trigger_entry)) 1646 return -EINVAL; 1647 1648 return trigger_entry->ops->enable(trigger_entry, mlxsw_sp_port, tc); 1649 } 1650 1651 void mlxsw_sp_span_trigger_disable(struct mlxsw_sp_port *mlxsw_sp_port, 1652 enum mlxsw_sp_span_trigger trigger, u8 tc) 1653 { 1654 struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; 1655 struct mlxsw_sp_span_trigger_entry *trigger_entry; 1656 1657 ASSERT_RTNL(); 1658 1659 trigger_entry = mlxsw_sp_span_trigger_entry_find(mlxsw_sp->span, 1660 trigger, 1661 mlxsw_sp_port); 1662 if (WARN_ON_ONCE(!trigger_entry)) 1663 return; 1664 1665 return trigger_entry->ops->disable(trigger_entry, mlxsw_sp_port, tc); 1666 } 1667 1668 bool mlxsw_sp_span_trigger_is_ingress(enum mlxsw_sp_span_trigger trigger) 1669 { 1670 switch (trigger) { 1671 case MLXSW_SP_SPAN_TRIGGER_INGRESS: 1672 case MLXSW_SP_SPAN_TRIGGER_EARLY_DROP: 1673 case MLXSW_SP_SPAN_TRIGGER_TAIL_DROP: 1674 return true; 1675 case MLXSW_SP_SPAN_TRIGGER_EGRESS: 1676 case MLXSW_SP_SPAN_TRIGGER_ECN: 1677 return false; 1678 } 1679 1680 WARN_ON_ONCE(1); 1681 return false; 1682 } 1683 1684 static int mlxsw_sp1_span_init(struct mlxsw_sp *mlxsw_sp) 1685 { 1686 size_t arr_size = ARRAY_SIZE(mlxsw_sp1_span_entry_ops_arr); 1687 1688 /* Must be first to avoid NULL pointer dereference by subsequent 1689 * can_handle() callbacks. 1690 */ 1691 if (WARN_ON(mlxsw_sp1_span_entry_ops_arr[0] != 1692 &mlxsw_sp1_span_entry_ops_cpu)) 1693 return -EINVAL; 1694 1695 mlxsw_sp->span->span_trigger_ops_arr = mlxsw_sp1_span_trigger_ops_arr; 1696 mlxsw_sp->span->span_entry_ops_arr = mlxsw_sp1_span_entry_ops_arr; 1697 mlxsw_sp->span->span_entry_ops_arr_size = arr_size; 1698 1699 return 0; 1700 } 1701 1702 static int mlxsw_sp1_span_policer_id_base_set(struct mlxsw_sp *mlxsw_sp, 1703 u16 policer_id_base) 1704 { 1705 return -EOPNOTSUPP; 1706 } 1707 1708 const struct mlxsw_sp_span_ops mlxsw_sp1_span_ops = { 1709 .init = mlxsw_sp1_span_init, 1710 .policer_id_base_set = mlxsw_sp1_span_policer_id_base_set, 1711 }; 1712 1713 static int mlxsw_sp2_span_init(struct mlxsw_sp *mlxsw_sp) 1714 { 1715 size_t arr_size = ARRAY_SIZE(mlxsw_sp2_span_entry_ops_arr); 1716 1717 /* Must be first to avoid NULL pointer dereference by subsequent 1718 * can_handle() callbacks. 1719 */ 1720 if (WARN_ON(mlxsw_sp2_span_entry_ops_arr[0] != 1721 &mlxsw_sp2_span_entry_ops_cpu)) 1722 return -EINVAL; 1723 1724 mlxsw_sp->span->span_trigger_ops_arr = mlxsw_sp2_span_trigger_ops_arr; 1725 mlxsw_sp->span->span_entry_ops_arr = mlxsw_sp2_span_entry_ops_arr; 1726 mlxsw_sp->span->span_entry_ops_arr_size = arr_size; 1727 1728 return 0; 1729 } 1730 1731 #define MLXSW_SP2_SPAN_EG_MIRROR_BUFFER_FACTOR 38 1732 #define MLXSW_SP3_SPAN_EG_MIRROR_BUFFER_FACTOR 50 1733 1734 static int mlxsw_sp2_span_policer_id_base_set(struct mlxsw_sp *mlxsw_sp, 1735 u16 policer_id_base) 1736 { 1737 char mogcr_pl[MLXSW_REG_MOGCR_LEN] = {0}; 1738 int err; 1739 1740 err = mlxsw_reg_query(mlxsw_sp->core, MLXSW_REG(mogcr), mogcr_pl); 1741 if (err) 1742 return err; 1743 1744 mlxsw_reg_mogcr_mirroring_pid_base_set(mogcr_pl, policer_id_base); 1745 return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(mogcr), mogcr_pl); 1746 } 1747 1748 const struct mlxsw_sp_span_ops mlxsw_sp2_span_ops = { 1749 .init = mlxsw_sp2_span_init, 1750 .policer_id_base_set = mlxsw_sp2_span_policer_id_base_set, 1751 }; 1752 1753 const struct mlxsw_sp_span_ops mlxsw_sp3_span_ops = { 1754 .init = mlxsw_sp2_span_init, 1755 .policer_id_base_set = mlxsw_sp2_span_policer_id_base_set, 1756 }; 1757