linux/drivers/net/dsa/bcm_sf2_cfp.c
<<
>>
Prefs
   1/*
   2 * Broadcom Starfighter 2 DSA switch CFP support
   3 *
   4 * Copyright (C) 2016, Broadcom
   5 *
   6 * This program is free software; you can redistribute it and/or modify
   7 * it under the terms of the GNU General Public License as published by
   8 * the Free Software Foundation; either version 2 of the License, or
   9 * (at your option) any later version.
  10 */
  11
  12#include <linux/list.h>
  13#include <linux/ethtool.h>
  14#include <linux/if_ether.h>
  15#include <linux/in.h>
  16#include <linux/netdevice.h>
  17#include <net/dsa.h>
  18#include <linux/bitmap.h>
  19
  20#include "bcm_sf2.h"
  21#include "bcm_sf2_regs.h"
  22
  23struct cfp_rule {
  24        int port;
  25        struct ethtool_rx_flow_spec fs;
  26        struct list_head next;
  27};
  28
  29struct cfp_udf_slice_layout {
  30        u8 slices[UDFS_PER_SLICE];
  31        u32 mask_value;
  32        u32 base_offset;
  33};
  34
  35struct cfp_udf_layout {
  36        struct cfp_udf_slice_layout udfs[UDF_NUM_SLICES];
  37};
  38
  39static const u8 zero_slice[UDFS_PER_SLICE] = { };
  40
  41/* UDF slices layout for a TCPv4/UDPv4 specification */
  42static const struct cfp_udf_layout udf_tcpip4_layout = {
  43        .udfs = {
  44                [1] = {
  45                        .slices = {
  46                                /* End of L2, byte offset 12, src IP[0:15] */
  47                                CFG_UDF_EOL2 | 6,
  48                                /* End of L2, byte offset 14, src IP[16:31] */
  49                                CFG_UDF_EOL2 | 7,
  50                                /* End of L2, byte offset 16, dst IP[0:15] */
  51                                CFG_UDF_EOL2 | 8,
  52                                /* End of L2, byte offset 18, dst IP[16:31] */
  53                                CFG_UDF_EOL2 | 9,
  54                                /* End of L3, byte offset 0, src port */
  55                                CFG_UDF_EOL3 | 0,
  56                                /* End of L3, byte offset 2, dst port */
  57                                CFG_UDF_EOL3 | 1,
  58                                0, 0, 0
  59                        },
  60                        .mask_value = L3_FRAMING_MASK | IPPROTO_MASK | IP_FRAG,
  61                        .base_offset = CORE_UDF_0_A_0_8_PORT_0 + UDF_SLICE_OFFSET,
  62                },
  63        },
  64};
  65
  66/* UDF slices layout for a TCPv6/UDPv6 specification */
  67static const struct cfp_udf_layout udf_tcpip6_layout = {
  68        .udfs = {
  69                [0] = {
  70                        .slices = {
  71                                /* End of L2, byte offset 8, src IP[0:15] */
  72                                CFG_UDF_EOL2 | 4,
  73                                /* End of L2, byte offset 10, src IP[16:31] */
  74                                CFG_UDF_EOL2 | 5,
  75                                /* End of L2, byte offset 12, src IP[32:47] */
  76                                CFG_UDF_EOL2 | 6,
  77                                /* End of L2, byte offset 14, src IP[48:63] */
  78                                CFG_UDF_EOL2 | 7,
  79                                /* End of L2, byte offset 16, src IP[64:79] */
  80                                CFG_UDF_EOL2 | 8,
  81                                /* End of L2, byte offset 18, src IP[80:95] */
  82                                CFG_UDF_EOL2 | 9,
  83                                /* End of L2, byte offset 20, src IP[96:111] */
  84                                CFG_UDF_EOL2 | 10,
  85                                /* End of L2, byte offset 22, src IP[112:127] */
  86                                CFG_UDF_EOL2 | 11,
  87                                /* End of L3, byte offset 0, src port */
  88                                CFG_UDF_EOL3 | 0,
  89                        },
  90                        .mask_value = L3_FRAMING_MASK | IPPROTO_MASK | IP_FRAG,
  91                        .base_offset = CORE_UDF_0_B_0_8_PORT_0,
  92                },
  93                [3] = {
  94                        .slices = {
  95                                /* End of L2, byte offset 24, dst IP[0:15] */
  96                                CFG_UDF_EOL2 | 12,
  97                                /* End of L2, byte offset 26, dst IP[16:31] */
  98                                CFG_UDF_EOL2 | 13,
  99                                /* End of L2, byte offset 28, dst IP[32:47] */
 100                                CFG_UDF_EOL2 | 14,
 101                                /* End of L2, byte offset 30, dst IP[48:63] */
 102                                CFG_UDF_EOL2 | 15,
 103                                /* End of L2, byte offset 32, dst IP[64:79] */
 104                                CFG_UDF_EOL2 | 16,
 105                                /* End of L2, byte offset 34, dst IP[80:95] */
 106                                CFG_UDF_EOL2 | 17,
 107                                /* End of L2, byte offset 36, dst IP[96:111] */
 108                                CFG_UDF_EOL2 | 18,
 109                                /* End of L2, byte offset 38, dst IP[112:127] */
 110                                CFG_UDF_EOL2 | 19,
 111                                /* End of L3, byte offset 2, dst port */
 112                                CFG_UDF_EOL3 | 1,
 113                        },
 114                        .mask_value = L3_FRAMING_MASK | IPPROTO_MASK | IP_FRAG,
 115                        .base_offset = CORE_UDF_0_D_0_11_PORT_0,
 116                },
 117        },
 118};
 119
 120static inline unsigned int bcm_sf2_get_num_udf_slices(const u8 *layout)
 121{
 122        unsigned int i, count = 0;
 123
 124        for (i = 0; i < UDFS_PER_SLICE; i++) {
 125                if (layout[i] != 0)
 126                        count++;
 127        }
 128
 129        return count;
 130}
 131
 132static inline u32 udf_upper_bits(unsigned int num_udf)
 133{
 134        return GENMASK(num_udf - 1, 0) >> (UDFS_PER_SLICE - 1);
 135}
 136
 137static inline u32 udf_lower_bits(unsigned int num_udf)
 138{
 139        return (u8)GENMASK(num_udf - 1, 0);
 140}
 141
 142static unsigned int bcm_sf2_get_slice_number(const struct cfp_udf_layout *l,
 143                                             unsigned int start)
 144{
 145        const struct cfp_udf_slice_layout *slice_layout;
 146        unsigned int slice_idx;
 147
 148        for (slice_idx = start; slice_idx < UDF_NUM_SLICES; slice_idx++) {
 149                slice_layout = &l->udfs[slice_idx];
 150                if (memcmp(slice_layout->slices, zero_slice,
 151                           sizeof(zero_slice)))
 152                        break;
 153        }
 154
 155        return slice_idx;
 156}
 157
 158static void bcm_sf2_cfp_udf_set(struct bcm_sf2_priv *priv,
 159                                const struct cfp_udf_layout *layout,
 160                                unsigned int slice_num)
 161{
 162        u32 offset = layout->udfs[slice_num].base_offset;
 163        unsigned int i;
 164
 165        for (i = 0; i < UDFS_PER_SLICE; i++)
 166                core_writel(priv, layout->udfs[slice_num].slices[i],
 167                            offset + i * 4);
 168}
 169
 170static int bcm_sf2_cfp_op(struct bcm_sf2_priv *priv, unsigned int op)
 171{
 172        unsigned int timeout = 1000;
 173        u32 reg;
 174
 175        reg = core_readl(priv, CORE_CFP_ACC);
 176        reg &= ~(OP_SEL_MASK | RAM_SEL_MASK);
 177        reg |= OP_STR_DONE | op;
 178        core_writel(priv, reg, CORE_CFP_ACC);
 179
 180        do {
 181                reg = core_readl(priv, CORE_CFP_ACC);
 182                if (!(reg & OP_STR_DONE))
 183                        break;
 184
 185                cpu_relax();
 186        } while (timeout--);
 187
 188        if (!timeout)
 189                return -ETIMEDOUT;
 190
 191        return 0;
 192}
 193
 194static inline void bcm_sf2_cfp_rule_addr_set(struct bcm_sf2_priv *priv,
 195                                             unsigned int addr)
 196{
 197        u32 reg;
 198
 199        WARN_ON(addr >= priv->num_cfp_rules);
 200
 201        reg = core_readl(priv, CORE_CFP_ACC);
 202        reg &= ~(XCESS_ADDR_MASK << XCESS_ADDR_SHIFT);
 203        reg |= addr << XCESS_ADDR_SHIFT;
 204        core_writel(priv, reg, CORE_CFP_ACC);
 205}
 206
 207static inline unsigned int bcm_sf2_cfp_rule_size(struct bcm_sf2_priv *priv)
 208{
 209        /* Entry #0 is reserved */
 210        return priv->num_cfp_rules - 1;
 211}
 212
 213static int bcm_sf2_cfp_act_pol_set(struct bcm_sf2_priv *priv,
 214                                   unsigned int rule_index,
 215                                   unsigned int port_num,
 216                                   unsigned int queue_num,
 217                                   bool fwd_map_change)
 218{
 219        int ret;
 220        u32 reg;
 221
 222        /* Replace ARL derived destination with DST_MAP derived, define
 223         * which port and queue this should be forwarded to.
 224         */
 225        if (fwd_map_change)
 226                reg = CHANGE_FWRD_MAP_IB_REP_ARL |
 227                      BIT(port_num + DST_MAP_IB_SHIFT) |
 228                      CHANGE_TC | queue_num << NEW_TC_SHIFT;
 229        else
 230                reg = 0;
 231
 232        core_writel(priv, reg, CORE_ACT_POL_DATA0);
 233
 234        /* Set classification ID that needs to be put in Broadcom tag */
 235        core_writel(priv, rule_index << CHAIN_ID_SHIFT, CORE_ACT_POL_DATA1);
 236
 237        core_writel(priv, 0, CORE_ACT_POL_DATA2);
 238
 239        /* Configure policer RAM now */
 240        ret = bcm_sf2_cfp_op(priv, OP_SEL_WRITE | ACT_POL_RAM);
 241        if (ret) {
 242                pr_err("Policer entry at %d failed\n", rule_index);
 243                return ret;
 244        }
 245
 246        /* Disable the policer */
 247        core_writel(priv, POLICER_MODE_DISABLE, CORE_RATE_METER0);
 248
 249        /* Now the rate meter */
 250        ret = bcm_sf2_cfp_op(priv, OP_SEL_WRITE | RATE_METER_RAM);
 251        if (ret) {
 252                pr_err("Meter entry at %d failed\n", rule_index);
 253                return ret;
 254        }
 255
 256        return 0;
 257}
 258
 259static void bcm_sf2_cfp_slice_ipv4(struct bcm_sf2_priv *priv,
 260                                   struct ethtool_tcpip4_spec *v4_spec,
 261                                   unsigned int slice_num,
 262                                   bool mask)
 263{
 264        u32 reg, offset;
 265
 266        /* C-Tag                [31:24]
 267         * UDF_n_A8             [23:8]
 268         * UDF_n_A7             [7:0]
 269         */
 270        reg = 0;
 271        if (mask)
 272                offset = CORE_CFP_MASK_PORT(4);
 273        else
 274                offset = CORE_CFP_DATA_PORT(4);
 275        core_writel(priv, reg, offset);
 276
 277        /* UDF_n_A7             [31:24]
 278         * UDF_n_A6             [23:8]
 279         * UDF_n_A5             [7:0]
 280         */
 281        reg = be16_to_cpu(v4_spec->pdst) >> 8;
 282        if (mask)
 283                offset = CORE_CFP_MASK_PORT(3);
 284        else
 285                offset = CORE_CFP_DATA_PORT(3);
 286        core_writel(priv, reg, offset);
 287
 288        /* UDF_n_A5             [31:24]
 289         * UDF_n_A4             [23:8]
 290         * UDF_n_A3             [7:0]
 291         */
 292        reg = (be16_to_cpu(v4_spec->pdst) & 0xff) << 24 |
 293              (u32)be16_to_cpu(v4_spec->psrc) << 8 |
 294              (be32_to_cpu(v4_spec->ip4dst) & 0x0000ff00) >> 8;
 295        if (mask)
 296                offset = CORE_CFP_MASK_PORT(2);
 297        else
 298                offset = CORE_CFP_DATA_PORT(2);
 299        core_writel(priv, reg, offset);
 300
 301        /* UDF_n_A3             [31:24]
 302         * UDF_n_A2             [23:8]
 303         * UDF_n_A1             [7:0]
 304         */
 305        reg = (u32)(be32_to_cpu(v4_spec->ip4dst) & 0xff) << 24 |
 306              (u32)(be32_to_cpu(v4_spec->ip4dst) >> 16) << 8 |
 307              (be32_to_cpu(v4_spec->ip4src) & 0x0000ff00) >> 8;
 308        if (mask)
 309                offset = CORE_CFP_MASK_PORT(1);
 310        else
 311                offset = CORE_CFP_DATA_PORT(1);
 312        core_writel(priv, reg, offset);
 313
 314        /* UDF_n_A1             [31:24]
 315         * UDF_n_A0             [23:8]
 316         * Reserved             [7:4]
 317         * Slice ID             [3:2]
 318         * Slice valid          [1:0]
 319         */
 320        reg = (u32)(be32_to_cpu(v4_spec->ip4src) & 0xff) << 24 |
 321              (u32)(be32_to_cpu(v4_spec->ip4src) >> 16) << 8 |
 322              SLICE_NUM(slice_num) | SLICE_VALID;
 323        if (mask)
 324                offset = CORE_CFP_MASK_PORT(0);
 325        else
 326                offset = CORE_CFP_DATA_PORT(0);
 327        core_writel(priv, reg, offset);
 328}
 329
 330static int bcm_sf2_cfp_ipv4_rule_set(struct bcm_sf2_priv *priv, int port,
 331                                     unsigned int port_num,
 332                                     unsigned int queue_num,
 333                                     struct ethtool_rx_flow_spec *fs)
 334{
 335        struct ethtool_tcpip4_spec *v4_spec, *v4_m_spec;
 336        const struct cfp_udf_layout *layout;
 337        unsigned int slice_num, rule_index;
 338        u8 ip_proto, ip_frag;
 339        u8 num_udf;
 340        u32 reg;
 341        int ret;
 342
 343        switch (fs->flow_type & ~FLOW_EXT) {
 344        case TCP_V4_FLOW:
 345                ip_proto = IPPROTO_TCP;
 346                v4_spec = &fs->h_u.tcp_ip4_spec;
 347                v4_m_spec = &fs->m_u.tcp_ip4_spec;
 348                break;
 349        case UDP_V4_FLOW:
 350                ip_proto = IPPROTO_UDP;
 351                v4_spec = &fs->h_u.udp_ip4_spec;
 352                v4_m_spec = &fs->m_u.udp_ip4_spec;
 353                break;
 354        default:
 355                return -EINVAL;
 356        }
 357
 358        ip_frag = be32_to_cpu(fs->m_ext.data[0]);
 359
 360        /* Locate the first rule available */
 361        if (fs->location == RX_CLS_LOC_ANY)
 362                rule_index = find_first_zero_bit(priv->cfp.used,
 363                                                 priv->num_cfp_rules);
 364        else
 365                rule_index = fs->location;
 366
 367        if (rule_index > bcm_sf2_cfp_rule_size(priv))
 368                return -ENOSPC;
 369
 370        layout = &udf_tcpip4_layout;
 371        /* We only use one UDF slice for now */
 372        slice_num = bcm_sf2_get_slice_number(layout, 0);
 373        if (slice_num == UDF_NUM_SLICES)
 374                return -EINVAL;
 375
 376        num_udf = bcm_sf2_get_num_udf_slices(layout->udfs[slice_num].slices);
 377
 378        /* Apply the UDF layout for this filter */
 379        bcm_sf2_cfp_udf_set(priv, layout, slice_num);
 380
 381        /* Apply to all packets received through this port */
 382        core_writel(priv, BIT(port), CORE_CFP_DATA_PORT(7));
 383
 384        /* Source port map match */
 385        core_writel(priv, 0xff, CORE_CFP_MASK_PORT(7));
 386
 387        /* S-Tag status         [31:30]
 388         * C-Tag status         [29:28]
 389         * L2 framing           [27:26]
 390         * L3 framing           [25:24]
 391         * IP ToS               [23:16]
 392         * IP proto             [15:08]
 393         * IP Fragm             [7]
 394         * Non 1st frag         [6]
 395         * IP Authen            [5]
 396         * TTL range            [4:3]
 397         * PPPoE session        [2]
 398         * Reserved             [1]
 399         * UDF_Valid[8]         [0]
 400         */
 401        core_writel(priv, v4_spec->tos << IPTOS_SHIFT |
 402                    ip_proto << IPPROTO_SHIFT | ip_frag << IP_FRAG_SHIFT |
 403                    udf_upper_bits(num_udf),
 404                    CORE_CFP_DATA_PORT(6));
 405
 406        /* Mask with the specific layout for IPv4 packets */
 407        core_writel(priv, layout->udfs[slice_num].mask_value |
 408                    udf_upper_bits(num_udf), CORE_CFP_MASK_PORT(6));
 409
 410        /* UDF_Valid[7:0]       [31:24]
 411         * S-Tag                [23:8]
 412         * C-Tag                [7:0]
 413         */
 414        core_writel(priv, udf_lower_bits(num_udf) << 24, CORE_CFP_DATA_PORT(5));
 415
 416        /* Mask all but valid UDFs */
 417        core_writel(priv, udf_lower_bits(num_udf) << 24, CORE_CFP_MASK_PORT(5));
 418
 419        /* Program the match and the mask */
 420        bcm_sf2_cfp_slice_ipv4(priv, v4_spec, slice_num, false);
 421        bcm_sf2_cfp_slice_ipv4(priv, v4_m_spec, SLICE_NUM_MASK, true);
 422
 423        /* Insert into TCAM now */
 424        bcm_sf2_cfp_rule_addr_set(priv, rule_index);
 425
 426        ret = bcm_sf2_cfp_op(priv, OP_SEL_WRITE | TCAM_SEL);
 427        if (ret) {
 428                pr_err("TCAM entry at addr %d failed\n", rule_index);
 429                return ret;
 430        }
 431
 432        /* Insert into Action and policer RAMs now */
 433        ret = bcm_sf2_cfp_act_pol_set(priv, rule_index, port_num,
 434                                      queue_num, true);
 435        if (ret)
 436                return ret;
 437
 438        /* Turn on CFP for this rule now */
 439        reg = core_readl(priv, CORE_CFP_CTL_REG);
 440        reg |= BIT(port);
 441        core_writel(priv, reg, CORE_CFP_CTL_REG);
 442
 443        /* Flag the rule as being used and return it */
 444        set_bit(rule_index, priv->cfp.used);
 445        set_bit(rule_index, priv->cfp.unique);
 446        fs->location = rule_index;
 447
 448        return 0;
 449}
 450
 451static void bcm_sf2_cfp_slice_ipv6(struct bcm_sf2_priv *priv,
 452                                   const __be32 *ip6_addr, const __be16 port,
 453                                   unsigned int slice_num,
 454                                   bool mask)
 455{
 456        u32 reg, tmp, val, offset;
 457
 458        /* C-Tag                [31:24]
 459         * UDF_n_B8             [23:8]  (port)
 460         * UDF_n_B7 (upper)     [7:0]   (addr[15:8])
 461         */
 462        reg = be32_to_cpu(ip6_addr[3]);
 463        val = (u32)be16_to_cpu(port) << 8 | ((reg >> 8) & 0xff);
 464        if (mask)
 465                offset = CORE_CFP_MASK_PORT(4);
 466        else
 467                offset = CORE_CFP_DATA_PORT(4);
 468        core_writel(priv, val, offset);
 469
 470        /* UDF_n_B7 (lower)     [31:24] (addr[7:0])
 471         * UDF_n_B6             [23:8] (addr[31:16])
 472         * UDF_n_B5 (upper)     [7:0] (addr[47:40])
 473         */
 474        tmp = be32_to_cpu(ip6_addr[2]);
 475        val = (u32)(reg & 0xff) << 24 | (u32)(reg >> 16) << 8 |
 476              ((tmp >> 8) & 0xff);
 477        if (mask)
 478                offset = CORE_CFP_MASK_PORT(3);
 479        else
 480                offset = CORE_CFP_DATA_PORT(3);
 481        core_writel(priv, val, offset);
 482
 483        /* UDF_n_B5 (lower)     [31:24] (addr[39:32])
 484         * UDF_n_B4             [23:8] (addr[63:48])
 485         * UDF_n_B3 (upper)     [7:0] (addr[79:72])
 486         */
 487        reg = be32_to_cpu(ip6_addr[1]);
 488        val = (u32)(tmp & 0xff) << 24 | (u32)(tmp >> 16) << 8 |
 489              ((reg >> 8) & 0xff);
 490        if (mask)
 491                offset = CORE_CFP_MASK_PORT(2);
 492        else
 493                offset = CORE_CFP_DATA_PORT(2);
 494        core_writel(priv, val, offset);
 495
 496        /* UDF_n_B3 (lower)     [31:24] (addr[71:64])
 497         * UDF_n_B2             [23:8] (addr[95:80])
 498         * UDF_n_B1 (upper)     [7:0] (addr[111:104])
 499         */
 500        tmp = be32_to_cpu(ip6_addr[0]);
 501        val = (u32)(reg & 0xff) << 24 | (u32)(reg >> 16) << 8 |
 502              ((tmp >> 8) & 0xff);
 503        if (mask)
 504                offset = CORE_CFP_MASK_PORT(1);
 505        else
 506                offset = CORE_CFP_DATA_PORT(1);
 507        core_writel(priv, val, offset);
 508
 509        /* UDF_n_B1 (lower)     [31:24] (addr[103:96])
 510         * UDF_n_B0             [23:8] (addr[127:112])
 511         * Reserved             [7:4]
 512         * Slice ID             [3:2]
 513         * Slice valid          [1:0]
 514         */
 515        reg = (u32)(tmp & 0xff) << 24 | (u32)(tmp >> 16) << 8 |
 516               SLICE_NUM(slice_num) | SLICE_VALID;
 517        if (mask)
 518                offset = CORE_CFP_MASK_PORT(0);
 519        else
 520                offset = CORE_CFP_DATA_PORT(0);
 521        core_writel(priv, reg, offset);
 522}
 523
 524static struct cfp_rule *bcm_sf2_cfp_rule_find(struct bcm_sf2_priv *priv,
 525                                              int port, u32 location)
 526{
 527        struct cfp_rule *rule = NULL;
 528
 529        list_for_each_entry(rule, &priv->cfp.rules_list, next) {
 530                if (rule->port == port && rule->fs.location == location)
 531                        break;
 532        }
 533
 534        return rule;
 535}
 536
 537static int bcm_sf2_cfp_rule_cmp(struct bcm_sf2_priv *priv, int port,
 538                                struct ethtool_rx_flow_spec *fs)
 539{
 540        struct cfp_rule *rule = NULL;
 541        size_t fs_size = 0;
 542        int ret = 1;
 543
 544        if (list_empty(&priv->cfp.rules_list))
 545                return ret;
 546
 547        list_for_each_entry(rule, &priv->cfp.rules_list, next) {
 548                ret = 1;
 549                if (rule->port != port)
 550                        continue;
 551
 552                if (rule->fs.flow_type != fs->flow_type ||
 553                    rule->fs.ring_cookie != fs->ring_cookie ||
 554                    rule->fs.m_ext.data[0] != fs->m_ext.data[0])
 555                        continue;
 556
 557                switch (fs->flow_type & ~FLOW_EXT) {
 558                case TCP_V6_FLOW:
 559                case UDP_V6_FLOW:
 560                        fs_size = sizeof(struct ethtool_tcpip6_spec);
 561                        break;
 562                case TCP_V4_FLOW:
 563                case UDP_V4_FLOW:
 564                        fs_size = sizeof(struct ethtool_tcpip4_spec);
 565                        break;
 566                default:
 567                        continue;
 568                }
 569
 570                ret = memcmp(&rule->fs.h_u, &fs->h_u, fs_size);
 571                ret |= memcmp(&rule->fs.m_u, &fs->m_u, fs_size);
 572                if (ret == 0)
 573                        break;
 574        }
 575
 576        return ret;
 577}
 578
 579static int bcm_sf2_cfp_ipv6_rule_set(struct bcm_sf2_priv *priv, int port,
 580                                     unsigned int port_num,
 581                                     unsigned int queue_num,
 582                                     struct ethtool_rx_flow_spec *fs)
 583{
 584        struct ethtool_tcpip6_spec *v6_spec, *v6_m_spec;
 585        unsigned int slice_num, rule_index[2];
 586        const struct cfp_udf_layout *layout;
 587        u8 ip_proto, ip_frag;
 588        int ret = 0;
 589        u8 num_udf;
 590        u32 reg;
 591
 592        switch (fs->flow_type & ~FLOW_EXT) {
 593        case TCP_V6_FLOW:
 594                ip_proto = IPPROTO_TCP;
 595                v6_spec = &fs->h_u.tcp_ip6_spec;
 596                v6_m_spec = &fs->m_u.tcp_ip6_spec;
 597                break;
 598        case UDP_V6_FLOW:
 599                ip_proto = IPPROTO_UDP;
 600                v6_spec = &fs->h_u.udp_ip6_spec;
 601                v6_m_spec = &fs->m_u.udp_ip6_spec;
 602                break;
 603        default:
 604                return -EINVAL;
 605        }
 606
 607        ip_frag = be32_to_cpu(fs->m_ext.data[0]);
 608
 609        layout = &udf_tcpip6_layout;
 610        slice_num = bcm_sf2_get_slice_number(layout, 0);
 611        if (slice_num == UDF_NUM_SLICES)
 612                return -EINVAL;
 613
 614        num_udf = bcm_sf2_get_num_udf_slices(layout->udfs[slice_num].slices);
 615
 616        /* Negotiate two indexes, one for the second half which we are chained
 617         * from, which is what we will return to user-space, and a second one
 618         * which is used to store its first half. That first half does not
 619         * allow any choice of placement, so it just needs to find the next
 620         * available bit. We return the second half as fs->location because
 621         * that helps with the rule lookup later on since the second half is
 622         * chained from its first half, we can easily identify IPv6 CFP rules
 623         * by looking whether they carry a CHAIN_ID.
 624         *
 625         * We also want the second half to have a lower rule_index than its
 626         * first half because the HW search is by incrementing addresses.
 627         */
 628        if (fs->location == RX_CLS_LOC_ANY)
 629                rule_index[1] = find_first_zero_bit(priv->cfp.used,
 630                                                    priv->num_cfp_rules);
 631        else
 632                rule_index[1] = fs->location;
 633        if (rule_index[1] > bcm_sf2_cfp_rule_size(priv))
 634                return -ENOSPC;
 635
 636        /* Flag it as used (cleared on error path) such that we can immediately
 637         * obtain a second one to chain from.
 638         */
 639        set_bit(rule_index[1], priv->cfp.used);
 640
 641        rule_index[0] = find_first_zero_bit(priv->cfp.used,
 642                                            priv->num_cfp_rules);
 643        if (rule_index[0] > bcm_sf2_cfp_rule_size(priv)) {
 644                ret = -ENOSPC;
 645                goto out_err;
 646        }
 647
 648        /* Apply the UDF layout for this filter */
 649        bcm_sf2_cfp_udf_set(priv, layout, slice_num);
 650
 651        /* Apply to all packets received through this port */
 652        core_writel(priv, BIT(port), CORE_CFP_DATA_PORT(7));
 653
 654        /* Source port map match */
 655        core_writel(priv, 0xff, CORE_CFP_MASK_PORT(7));
 656
 657        /* S-Tag status         [31:30]
 658         * C-Tag status         [29:28]
 659         * L2 framing           [27:26]
 660         * L3 framing           [25:24]
 661         * IP ToS               [23:16]
 662         * IP proto             [15:08]
 663         * IP Fragm             [7]
 664         * Non 1st frag         [6]
 665         * IP Authen            [5]
 666         * TTL range            [4:3]
 667         * PPPoE session        [2]
 668         * Reserved             [1]
 669         * UDF_Valid[8]         [0]
 670         */
 671        reg = 1 << L3_FRAMING_SHIFT | ip_proto << IPPROTO_SHIFT |
 672                ip_frag << IP_FRAG_SHIFT | udf_upper_bits(num_udf);
 673        core_writel(priv, reg, CORE_CFP_DATA_PORT(6));
 674
 675        /* Mask with the specific layout for IPv6 packets including
 676         * UDF_Valid[8]
 677         */
 678        reg = layout->udfs[slice_num].mask_value | udf_upper_bits(num_udf);
 679        core_writel(priv, reg, CORE_CFP_MASK_PORT(6));
 680
 681        /* UDF_Valid[7:0]       [31:24]
 682         * S-Tag                [23:8]
 683         * C-Tag                [7:0]
 684         */
 685        core_writel(priv, udf_lower_bits(num_udf) << 24, CORE_CFP_DATA_PORT(5));
 686
 687        /* Mask all but valid UDFs */
 688        core_writel(priv, udf_lower_bits(num_udf) << 24, CORE_CFP_MASK_PORT(5));
 689
 690        /* Slice the IPv6 source address and port */
 691        bcm_sf2_cfp_slice_ipv6(priv, v6_spec->ip6src, v6_spec->psrc,
 692                                slice_num, false);
 693        bcm_sf2_cfp_slice_ipv6(priv, v6_m_spec->ip6src, v6_m_spec->psrc,
 694                                SLICE_NUM_MASK, true);
 695
 696        /* Insert into TCAM now because we need to insert a second rule */
 697        bcm_sf2_cfp_rule_addr_set(priv, rule_index[0]);
 698
 699        ret = bcm_sf2_cfp_op(priv, OP_SEL_WRITE | TCAM_SEL);
 700        if (ret) {
 701                pr_err("TCAM entry at addr %d failed\n", rule_index[0]);
 702                goto out_err;
 703        }
 704
 705        /* Insert into Action and policer RAMs now */
 706        ret = bcm_sf2_cfp_act_pol_set(priv, rule_index[0], port_num,
 707                                      queue_num, false);
 708        if (ret)
 709                goto out_err;
 710
 711        /* Now deal with the second slice to chain this rule */
 712        slice_num = bcm_sf2_get_slice_number(layout, slice_num + 1);
 713        if (slice_num == UDF_NUM_SLICES) {
 714                ret = -EINVAL;
 715                goto out_err;
 716        }
 717
 718        num_udf = bcm_sf2_get_num_udf_slices(layout->udfs[slice_num].slices);
 719
 720        /* Apply the UDF layout for this filter */
 721        bcm_sf2_cfp_udf_set(priv, layout, slice_num);
 722
 723        /* Chained rule, source port match is coming from the rule we are
 724         * chained from.
 725         */
 726        core_writel(priv, 0, CORE_CFP_DATA_PORT(7));
 727        core_writel(priv, 0, CORE_CFP_MASK_PORT(7));
 728
 729        /*
 730         * CHAIN ID             [31:24] chain to previous slice
 731         * Reserved             [23:20]
 732         * UDF_Valid[11:8]      [19:16]
 733         * UDF_Valid[7:0]       [15:8]
 734         * UDF_n_D11            [7:0]
 735         */
 736        reg = rule_index[0] << 24 | udf_upper_bits(num_udf) << 16 |
 737                udf_lower_bits(num_udf) << 8;
 738        core_writel(priv, reg, CORE_CFP_DATA_PORT(6));
 739
 740        /* Mask all except chain ID, UDF Valid[8] and UDF Valid[7:0] */
 741        reg = XCESS_ADDR_MASK << 24 | udf_upper_bits(num_udf) << 16 |
 742                udf_lower_bits(num_udf) << 8;
 743        core_writel(priv, reg, CORE_CFP_MASK_PORT(6));
 744
 745        /* Don't care */
 746        core_writel(priv, 0, CORE_CFP_DATA_PORT(5));
 747
 748        /* Mask all */
 749        core_writel(priv, 0, CORE_CFP_MASK_PORT(5));
 750
 751        bcm_sf2_cfp_slice_ipv6(priv, v6_spec->ip6dst, v6_spec->pdst, slice_num,
 752                               false);
 753        bcm_sf2_cfp_slice_ipv6(priv, v6_m_spec->ip6dst, v6_m_spec->pdst,
 754                               SLICE_NUM_MASK, true);
 755
 756        /* Insert into TCAM now */
 757        bcm_sf2_cfp_rule_addr_set(priv, rule_index[1]);
 758
 759        ret = bcm_sf2_cfp_op(priv, OP_SEL_WRITE | TCAM_SEL);
 760        if (ret) {
 761                pr_err("TCAM entry at addr %d failed\n", rule_index[1]);
 762                goto out_err;
 763        }
 764
 765        /* Insert into Action and policer RAMs now, set chain ID to
 766         * the one we are chained to
 767         */
 768        ret = bcm_sf2_cfp_act_pol_set(priv, rule_index[1], port_num,
 769                                      queue_num, true);
 770        if (ret)
 771                goto out_err;
 772
 773        /* Turn on CFP for this rule now */
 774        reg = core_readl(priv, CORE_CFP_CTL_REG);
 775        reg |= BIT(port);
 776        core_writel(priv, reg, CORE_CFP_CTL_REG);
 777
 778        /* Flag the second half rule as being used now, return it as the
 779         * location, and flag it as unique while dumping rules
 780         */
 781        set_bit(rule_index[0], priv->cfp.used);
 782        set_bit(rule_index[1], priv->cfp.unique);
 783        fs->location = rule_index[1];
 784
 785        return ret;
 786
 787out_err:
 788        clear_bit(rule_index[1], priv->cfp.used);
 789        return ret;
 790}
 791
 792static int bcm_sf2_cfp_rule_insert(struct dsa_switch *ds, int port,
 793                                   struct ethtool_rx_flow_spec *fs)
 794{
 795        struct bcm_sf2_priv *priv = bcm_sf2_to_priv(ds);
 796        s8 cpu_port = ds->ports[port].cpu_dp->index;
 797        __u64 ring_cookie = fs->ring_cookie;
 798        unsigned int queue_num, port_num;
 799        int ret;
 800
 801        /* This rule is a Wake-on-LAN filter and we must specifically
 802         * target the CPU port in order for it to be working.
 803         */
 804        if (ring_cookie == RX_CLS_FLOW_WAKE)
 805                ring_cookie = cpu_port * SF2_NUM_EGRESS_QUEUES;
 806
 807        /* We do not support discarding packets, check that the
 808         * destination port is enabled and that we are within the
 809         * number of ports supported by the switch
 810         */
 811        port_num = ring_cookie / SF2_NUM_EGRESS_QUEUES;
 812
 813        if (ring_cookie == RX_CLS_FLOW_DISC ||
 814            !(dsa_is_user_port(ds, port_num) ||
 815              dsa_is_cpu_port(ds, port_num)) ||
 816            port_num >= priv->hw_params.num_ports)
 817                return -EINVAL;
 818        /*
 819         * We have a small oddity where Port 6 just does not have a
 820         * valid bit here (so we substract by one).
 821         */
 822        queue_num = ring_cookie % SF2_NUM_EGRESS_QUEUES;
 823        if (port_num >= 7)
 824                port_num -= 1;
 825
 826        switch (fs->flow_type & ~FLOW_EXT) {
 827        case TCP_V4_FLOW:
 828        case UDP_V4_FLOW:
 829                ret = bcm_sf2_cfp_ipv4_rule_set(priv, port, port_num,
 830                                                queue_num, fs);
 831                break;
 832        case TCP_V6_FLOW:
 833        case UDP_V6_FLOW:
 834                ret = bcm_sf2_cfp_ipv6_rule_set(priv, port, port_num,
 835                                                queue_num, fs);
 836                break;
 837        default:
 838                ret = -EINVAL;
 839                break;
 840        }
 841
 842        return ret;
 843}
 844
 845static int bcm_sf2_cfp_rule_set(struct dsa_switch *ds, int port,
 846                                struct ethtool_rx_flow_spec *fs)
 847{
 848        struct bcm_sf2_priv *priv = bcm_sf2_to_priv(ds);
 849        struct cfp_rule *rule = NULL;
 850        int ret = -EINVAL;
 851
 852        /* Check for unsupported extensions */
 853        if ((fs->flow_type & FLOW_EXT) && (fs->m_ext.vlan_etype ||
 854             fs->m_ext.data[1]))
 855                return -EINVAL;
 856
 857        if (fs->location != RX_CLS_LOC_ANY &&
 858            test_bit(fs->location, priv->cfp.used))
 859                return -EBUSY;
 860
 861        if (fs->location != RX_CLS_LOC_ANY &&
 862            fs->location > bcm_sf2_cfp_rule_size(priv))
 863                return -EINVAL;
 864
 865        ret = bcm_sf2_cfp_rule_cmp(priv, port, fs);
 866        if (ret == 0)
 867                return -EEXIST;
 868
 869        rule = kzalloc(sizeof(*rule), GFP_KERNEL);
 870        if (!rule)
 871                return -ENOMEM;
 872
 873        ret = bcm_sf2_cfp_rule_insert(ds, port, fs);
 874        if (ret) {
 875                kfree(rule);
 876                return ret;
 877        }
 878
 879        rule->port = port;
 880        memcpy(&rule->fs, fs, sizeof(*fs));
 881        list_add_tail(&rule->next, &priv->cfp.rules_list);
 882
 883        return ret;
 884}
 885
 886static int bcm_sf2_cfp_rule_del_one(struct bcm_sf2_priv *priv, int port,
 887                                    u32 loc, u32 *next_loc)
 888{
 889        int ret;
 890        u32 reg;
 891
 892        /* Indicate which rule we want to read */
 893        bcm_sf2_cfp_rule_addr_set(priv, loc);
 894
 895        ret =  bcm_sf2_cfp_op(priv, OP_SEL_READ | TCAM_SEL);
 896        if (ret)
 897                return ret;
 898
 899        /* Check if this is possibly an IPv6 rule that would
 900         * indicate we need to delete its companion rule
 901         * as well
 902         */
 903        reg = core_readl(priv, CORE_CFP_DATA_PORT(6));
 904        if (next_loc)
 905                *next_loc = (reg >> 24) & CHAIN_ID_MASK;
 906
 907        /* Clear its valid bits */
 908        reg = core_readl(priv, CORE_CFP_DATA_PORT(0));
 909        reg &= ~SLICE_VALID;
 910        core_writel(priv, reg, CORE_CFP_DATA_PORT(0));
 911
 912        /* Write back this entry into the TCAM now */
 913        ret = bcm_sf2_cfp_op(priv, OP_SEL_WRITE | TCAM_SEL);
 914        if (ret)
 915                return ret;
 916
 917        clear_bit(loc, priv->cfp.used);
 918        clear_bit(loc, priv->cfp.unique);
 919
 920        return 0;
 921}
 922
 923static int bcm_sf2_cfp_rule_remove(struct bcm_sf2_priv *priv, int port,
 924                                   u32 loc)
 925{
 926        u32 next_loc = 0;
 927        int ret;
 928
 929        ret = bcm_sf2_cfp_rule_del_one(priv, port, loc, &next_loc);
 930        if (ret)
 931                return ret;
 932
 933        /* If this was an IPv6 rule, delete is companion rule too */
 934        if (next_loc)
 935                ret = bcm_sf2_cfp_rule_del_one(priv, port, next_loc, NULL);
 936
 937        return ret;
 938}
 939
 940static int bcm_sf2_cfp_rule_del(struct bcm_sf2_priv *priv, int port, u32 loc)
 941{
 942        struct cfp_rule *rule;
 943        int ret;
 944
 945        /* Refuse deleting unused rules, and those that are not unique since
 946         * that could leave IPv6 rules with one of the chained rule in the
 947         * table.
 948         */
 949        if (!test_bit(loc, priv->cfp.unique) || loc == 0)
 950                return -EINVAL;
 951
 952        rule = bcm_sf2_cfp_rule_find(priv, port, loc);
 953        if (!rule)
 954                return -EINVAL;
 955
 956        ret = bcm_sf2_cfp_rule_remove(priv, port, loc);
 957
 958        list_del(&rule->next);
 959        kfree(rule);
 960
 961        return ret;
 962}
 963
 964static void bcm_sf2_invert_masks(struct ethtool_rx_flow_spec *flow)
 965{
 966        unsigned int i;
 967
 968        for (i = 0; i < sizeof(flow->m_u); i++)
 969                flow->m_u.hdata[i] ^= 0xff;
 970
 971        flow->m_ext.vlan_etype ^= cpu_to_be16(~0);
 972        flow->m_ext.vlan_tci ^= cpu_to_be16(~0);
 973        flow->m_ext.data[0] ^= cpu_to_be32(~0);
 974        flow->m_ext.data[1] ^= cpu_to_be32(~0);
 975}
 976
 977static int bcm_sf2_cfp_rule_get(struct bcm_sf2_priv *priv, int port,
 978                                struct ethtool_rxnfc *nfc)
 979{
 980        struct cfp_rule *rule;
 981
 982        rule = bcm_sf2_cfp_rule_find(priv, port, nfc->fs.location);
 983        if (!rule)
 984                return -EINVAL;
 985
 986        memcpy(&nfc->fs, &rule->fs, sizeof(rule->fs));
 987
 988        bcm_sf2_invert_masks(&nfc->fs);
 989
 990        /* Put the TCAM size here */
 991        nfc->data = bcm_sf2_cfp_rule_size(priv);
 992
 993        return 0;
 994}
 995
 996/* We implement the search doing a TCAM search operation */
 997static int bcm_sf2_cfp_rule_get_all(struct bcm_sf2_priv *priv,
 998                                    int port, struct ethtool_rxnfc *nfc,
 999                                    u32 *rule_locs)
1000{
1001        unsigned int index = 1, rules_cnt = 0;
1002
1003        for_each_set_bit_from(index, priv->cfp.unique, priv->num_cfp_rules) {
1004                rule_locs[rules_cnt] = index;
1005                rules_cnt++;
1006        }
1007
1008        /* Put the TCAM size here */
1009        nfc->data = bcm_sf2_cfp_rule_size(priv);
1010        nfc->rule_cnt = rules_cnt;
1011
1012        return 0;
1013}
1014
1015int bcm_sf2_get_rxnfc(struct dsa_switch *ds, int port,
1016                      struct ethtool_rxnfc *nfc, u32 *rule_locs)
1017{
1018        struct net_device *p = ds->ports[port].cpu_dp->master;
1019        struct bcm_sf2_priv *priv = bcm_sf2_to_priv(ds);
1020        int ret = 0;
1021
1022        mutex_lock(&priv->cfp.lock);
1023
1024        switch (nfc->cmd) {
1025        case ETHTOOL_GRXCLSRLCNT:
1026                /* Subtract the default, unusable rule */
1027                nfc->rule_cnt = bitmap_weight(priv->cfp.unique,
1028                                              priv->num_cfp_rules) - 1;
1029                /* We support specifying rule locations */
1030                nfc->data |= RX_CLS_LOC_SPECIAL;
1031                break;
1032        case ETHTOOL_GRXCLSRULE:
1033                ret = bcm_sf2_cfp_rule_get(priv, port, nfc);
1034                break;
1035        case ETHTOOL_GRXCLSRLALL:
1036                ret = bcm_sf2_cfp_rule_get_all(priv, port, nfc, rule_locs);
1037                break;
1038        default:
1039                ret = -EOPNOTSUPP;
1040                break;
1041        }
1042
1043        mutex_unlock(&priv->cfp.lock);
1044
1045        if (ret)
1046                return ret;
1047
1048        /* Pass up the commands to the attached master network device */
1049        if (p->ethtool_ops->get_rxnfc) {
1050                ret = p->ethtool_ops->get_rxnfc(p, nfc, rule_locs);
1051                if (ret == -EOPNOTSUPP)
1052                        ret = 0;
1053        }
1054
1055        return ret;
1056}
1057
1058int bcm_sf2_set_rxnfc(struct dsa_switch *ds, int port,
1059                      struct ethtool_rxnfc *nfc)
1060{
1061        struct net_device *p = ds->ports[port].cpu_dp->master;
1062        struct bcm_sf2_priv *priv = bcm_sf2_to_priv(ds);
1063        int ret = 0;
1064
1065        mutex_lock(&priv->cfp.lock);
1066
1067        switch (nfc->cmd) {
1068        case ETHTOOL_SRXCLSRLINS:
1069                ret = bcm_sf2_cfp_rule_set(ds, port, &nfc->fs);
1070                break;
1071
1072        case ETHTOOL_SRXCLSRLDEL:
1073                ret = bcm_sf2_cfp_rule_del(priv, port, nfc->fs.location);
1074                break;
1075        default:
1076                ret = -EOPNOTSUPP;
1077                break;
1078        }
1079
1080        mutex_unlock(&priv->cfp.lock);
1081
1082        if (ret)
1083                return ret;
1084
1085        /* Pass up the commands to the attached master network device.
1086         * This can fail, so rollback the operation if we need to.
1087         */
1088        if (p->ethtool_ops->set_rxnfc) {
1089                ret = p->ethtool_ops->set_rxnfc(p, nfc);
1090                if (ret && ret != -EOPNOTSUPP) {
1091                        mutex_lock(&priv->cfp.lock);
1092                        bcm_sf2_cfp_rule_del(priv, port, nfc->fs.location);
1093                        mutex_unlock(&priv->cfp.lock);
1094                } else {
1095                        ret = 0;
1096                }
1097        }
1098
1099        return ret;
1100}
1101
1102int bcm_sf2_cfp_rst(struct bcm_sf2_priv *priv)
1103{
1104        unsigned int timeout = 1000;
1105        u32 reg;
1106
1107        reg = core_readl(priv, CORE_CFP_ACC);
1108        reg |= TCAM_RESET;
1109        core_writel(priv, reg, CORE_CFP_ACC);
1110
1111        do {
1112                reg = core_readl(priv, CORE_CFP_ACC);
1113                if (!(reg & TCAM_RESET))
1114                        break;
1115
1116                cpu_relax();
1117        } while (timeout--);
1118
1119        if (!timeout)
1120                return -ETIMEDOUT;
1121
1122        return 0;
1123}
1124
1125void bcm_sf2_cfp_exit(struct dsa_switch *ds)
1126{
1127        struct bcm_sf2_priv *priv = bcm_sf2_to_priv(ds);
1128        struct cfp_rule *rule, *n;
1129
1130        if (list_empty(&priv->cfp.rules_list))
1131                return;
1132
1133        list_for_each_entry_safe_reverse(rule, n, &priv->cfp.rules_list, next)
1134                bcm_sf2_cfp_rule_del(priv, rule->port, rule->fs.location);
1135}
1136
1137int bcm_sf2_cfp_resume(struct dsa_switch *ds)
1138{
1139        struct bcm_sf2_priv *priv = bcm_sf2_to_priv(ds);
1140        struct cfp_rule *rule;
1141        int ret = 0;
1142        u32 reg;
1143
1144        if (list_empty(&priv->cfp.rules_list))
1145                return ret;
1146
1147        reg = core_readl(priv, CORE_CFP_CTL_REG);
1148        reg &= ~CFP_EN_MAP_MASK;
1149        core_writel(priv, reg, CORE_CFP_CTL_REG);
1150
1151        ret = bcm_sf2_cfp_rst(priv);
1152        if (ret)
1153                return ret;
1154
1155        list_for_each_entry(rule, &priv->cfp.rules_list, next) {
1156                ret = bcm_sf2_cfp_rule_remove(priv, rule->port,
1157                                              rule->fs.location);
1158                if (ret) {
1159                        dev_err(ds->dev, "failed to remove rule\n");
1160                        return ret;
1161                }
1162
1163                ret = bcm_sf2_cfp_rule_insert(ds, rule->port, &rule->fs);
1164                if (ret) {
1165                        dev_err(ds->dev, "failed to restore rule\n");
1166                        return ret;
1167                }
1168        }
1169
1170        return ret;
1171}
1172