Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

net: dsa: bcm_sf2: Add support for matching VLAN TCI

Update relevant code paths to support the programming and matching of
VLAN TCI, this is the only member of the ethtool_flow_ext that we can
match, the switch does not permit matching the VLAN Ethernet Type field.

Signed-off-by: Florian Fainelli <f.fainelli@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>

authored by

Florian Fainelli and committed by
David S. Miller
7555020c c2d639d1

+38 -15
+38 -15
drivers/net/dsa/bcm_sf2_cfp.c
··· 261 261 static void bcm_sf2_cfp_slice_ipv4(struct bcm_sf2_priv *priv, 262 262 struct flow_dissector_key_ipv4_addrs *addrs, 263 263 struct flow_dissector_key_ports *ports, 264 + const __be16 vlan_tci, 264 265 unsigned int slice_num, u8 num_udf, 265 266 bool mask) 266 267 { ··· 271 270 * S-Tag [23:8] 272 271 * C-Tag [7:0] 273 272 */ 273 + reg = udf_lower_bits(num_udf) << 24 | be16_to_cpu(vlan_tci) >> 8; 274 274 if (mask) 275 - core_writel(priv, udf_lower_bits(num_udf) << 24, CORE_CFP_MASK_PORT(5)); 275 + core_writel(priv, reg, CORE_CFP_MASK_PORT(5)); 276 276 else 277 - core_writel(priv, udf_lower_bits(num_udf) << 24, CORE_CFP_DATA_PORT(5)); 277 + core_writel(priv, reg, CORE_CFP_DATA_PORT(5)); 278 278 279 279 /* C-Tag [31:24] 280 280 * UDF_n_A8 [23:8] 281 281 * UDF_n_A7 [7:0] 282 282 */ 283 - reg = 0; 283 + reg = (u32)(be16_to_cpu(vlan_tci) & 0xff) << 24; 284 284 if (mask) 285 285 offset = CORE_CFP_MASK_PORT(4); 286 286 else ··· 347 345 struct ethtool_rx_flow_spec *fs) 348 346 { 349 347 struct ethtool_rx_flow_spec_input input = {}; 348 + __be16 vlan_tci = 0 , vlan_m_tci = 0xffff; 350 349 const struct cfp_udf_layout *layout; 351 350 unsigned int slice_num, rule_index; 352 351 struct ethtool_rx_flow_rule *flow; ··· 371 368 } 372 369 373 370 ip_frag = !!(be32_to_cpu(fs->h_ext.data[0]) & 1); 371 + 372 + /* Extract VLAN TCI */ 373 + if (fs->flow_type & FLOW_EXT) { 374 + vlan_tci = fs->h_ext.vlan_tci; 375 + vlan_m_tci = fs->m_ext.vlan_tci; 376 + } 374 377 375 378 /* Locate the first rule available */ 376 379 if (fs->location == RX_CLS_LOC_ANY) ··· 440 431 udf_upper_bits(num_udf), CORE_CFP_MASK_PORT(6)); 441 432 442 433 /* Program the match and the mask */ 443 - bcm_sf2_cfp_slice_ipv4(priv, ipv4.key, ports.key, slice_num, 444 - num_udf, false); 445 - bcm_sf2_cfp_slice_ipv4(priv, ipv4.mask, ports.mask, SLICE_NUM_MASK, 446 - num_udf, true); 434 + bcm_sf2_cfp_slice_ipv4(priv, ipv4.key, ports.key, vlan_tci, 435 + slice_num, num_udf, false); 436 + bcm_sf2_cfp_slice_ipv4(priv, ipv4.mask, ports.mask, vlan_m_tci, 437 + SLICE_NUM_MASK, num_udf, true); 447 438 448 439 /* Insert into TCAM now */ 449 440 bcm_sf2_cfp_rule_addr_set(priv, rule_index); ··· 479 470 480 471 static void bcm_sf2_cfp_slice_ipv6(struct bcm_sf2_priv *priv, 481 472 const __be32 *ip6_addr, const __be16 port, 473 + const __be16 vlan_tci, 482 474 unsigned int slice_num, u32 udf_bits, 483 475 bool mask) 484 476 { ··· 489 479 * S-Tag [23:8] 490 480 * C-Tag [7:0] 491 481 */ 482 + reg = udf_bits << 24 | be16_to_cpu(vlan_tci) >> 8; 492 483 if (mask) 493 - core_writel(priv, udf_bits << 24, CORE_CFP_MASK_PORT(5)); 484 + core_writel(priv, reg, CORE_CFP_MASK_PORT(5)); 494 485 else 495 - core_writel(priv, udf_bits << 24, CORE_CFP_DATA_PORT(5)); 486 + core_writel(priv, reg, CORE_CFP_DATA_PORT(5)); 496 487 497 488 /* C-Tag [31:24] 498 489 * UDF_n_B8 [23:8] (port) ··· 501 490 */ 502 491 reg = be32_to_cpu(ip6_addr[3]); 503 492 val = (u32)be16_to_cpu(port) << 8 | ((reg >> 8) & 0xff); 493 + val |= (u32)(be16_to_cpu(vlan_tci) & 0xff) << 24; 504 494 if (mask) 505 495 offset = CORE_CFP_MASK_PORT(4); 506 496 else ··· 610 598 611 599 ret = memcmp(&rule->fs.h_u, &fs->h_u, fs_size); 612 600 ret |= memcmp(&rule->fs.m_u, &fs->m_u, fs_size); 601 + /* Compare VLAN TCI values as well */ 602 + if (rule->fs.flow_type & FLOW_EXT) { 603 + ret |= rule->fs.h_ext.vlan_tci != fs->h_ext.vlan_tci; 604 + ret |= rule->fs.m_ext.vlan_tci != fs->m_ext.vlan_tci; 605 + } 613 606 if (ret == 0) 614 607 break; 615 608 } ··· 628 611 struct ethtool_rx_flow_spec *fs) 629 612 { 630 613 struct ethtool_rx_flow_spec_input input = {}; 614 + __be16 vlan_tci = 0, vlan_m_tci = 0xffff; 631 615 unsigned int slice_num, rule_index[2]; 632 616 const struct cfp_udf_layout *layout; 633 617 struct ethtool_rx_flow_rule *flow; ··· 651 633 } 652 634 653 635 ip_frag = !!(be32_to_cpu(fs->h_ext.data[0]) & 1); 636 + 637 + /* Extract VLAN TCI */ 638 + if (fs->flow_type & FLOW_EXT) { 639 + vlan_tci = fs->h_ext.vlan_tci; 640 + vlan_m_tci = fs->m_ext.vlan_tci; 641 + } 654 642 655 643 layout = &udf_tcpip6_layout; 656 644 slice_num = bcm_sf2_get_slice_number(layout, 0); ··· 741 717 742 718 /* Slice the IPv6 source address and port */ 743 719 bcm_sf2_cfp_slice_ipv6(priv, ipv6.key->src.in6_u.u6_addr32, 744 - ports.key->src, slice_num, 720 + ports.key->src, vlan_tci, slice_num, 745 721 udf_lower_bits(num_udf), false); 746 722 bcm_sf2_cfp_slice_ipv6(priv, ipv6.mask->src.in6_u.u6_addr32, 747 - ports.mask->src, SLICE_NUM_MASK, 723 + ports.mask->src, vlan_m_tci, SLICE_NUM_MASK, 748 724 udf_lower_bits(num_udf), true); 749 725 750 726 /* Insert into TCAM now because we need to insert a second rule */ ··· 797 773 core_writel(priv, reg, CORE_CFP_MASK_PORT(6)); 798 774 799 775 bcm_sf2_cfp_slice_ipv6(priv, ipv6.key->dst.in6_u.u6_addr32, 800 - ports.key->dst, slice_num, 776 + ports.key->dst, 0, slice_num, 801 777 0, false); 802 778 bcm_sf2_cfp_slice_ipv6(priv, ipv6.mask->dst.in6_u.u6_addr32, 803 - ports.key->dst, SLICE_NUM_MASK, 779 + ports.key->dst, 0, SLICE_NUM_MASK, 804 780 0, true); 805 781 806 782 /* Insert into TCAM now */ ··· 902 878 int ret = -EINVAL; 903 879 904 880 /* Check for unsupported extensions */ 905 - if ((fs->flow_type & FLOW_EXT) || 906 - (fs->flow_type & FLOW_MAC_EXT) || 881 + if ((fs->flow_type & FLOW_MAC_EXT) || 907 882 fs->m_ext.data[1]) 908 883 return -EINVAL; 909 884