1. 09 9月, 2022 7 次提交
    • V
      net: mscc: ocelot: minimize definitions for stats · b69cf1c6
      Vladimir Oltean 提交于
      The current definition of struct ocelot_stat_layout is long-winded (4
      lines per entry, and we have hundreds of entries), so we could make an
      effort to use the C preprocessor and reduce the line count.
      
      Create an implicit correspondence between enum ocelot_reg, which tells
      us the register address (SYS_COUNT_RX_OCTETS etc) and enum ocelot_stat
      which allows us to index the ocelot->stats array (OCELOT_STAT_RX_OCTETS
      etc), and don't require us to specify both when we define what stats
      each switch family has.
      
      Create an OCELOT_STAT() macro that pairs only an enum ocelot_stat to an
      enum ocelot_reg, and an OCELOT_STAT_ETHTOOL() macro which also contains
      a name exported to the unstructured ethtool -S stringset API. For now,
      we define all counters as having the OCELOT_STAT_ETHTOOL() kind, but we
      will add more counters in the future which are not exported to the
      unstructured ethtool -S.
      Signed-off-by: NVladimir Oltean <vladimir.oltean@nxp.com>
      Signed-off-by: NDavid S. Miller <davem@davemloft.net>
      b69cf1c6
    • V
      net: mscc: ocelot: harmonize names of SYS_COUNT_TX_AGING and OCELOT_STAT_TX_AGED · be5c13f2
      Vladimir Oltean 提交于
      The hardware counter is called C_TX_AGED, so rename SYS_COUNT_TX_AGING
      to SYS_COUNT_TX_AGED. This will become important since we want to
      minimize the way in which we declare struct ocelot_stat_layout elements,
      using the C preprocessor.
      Signed-off-by: NVladimir Oltean <vladimir.oltean@nxp.com>
      Signed-off-by: NDavid S. Miller <davem@davemloft.net>
      be5c13f2
    • V
      net: mscc: ocelot: add support for all sorts of standardized counters present in DSA · e32036e1
      Vladimir Oltean 提交于
      DSA is integrated with the new standardized ethtool -S --groups option,
      but the felix driver only exports unstructured statistics.
      
      Reuse the array of 64-bit statistics collected by ocelot_check_stats_work(),
      but just export select values from it.
      
      Since ocelot_check_stats_work() runs periodically to avoid 32-bit
      overflow, and the ethtool calling context is sleepable, we update the
      64-bit stats one more time, to provide up-to-date values. The locking
      scheme with a mutex followed by a spinlock is a bit hard to digest, so
      we create and use a ocelot_port_stats_run() helper with a callback that
      populates the ethool stats group the caller is interested in.
      
      The exported stats are:
      ethtool -S swp0 --groups eth-phy
      ethtool -S swp0 --groups eth-mac
      ethtool -S swp0 --groups eth-ctrl
      ethtool -S swp0 --groups rmon
      ethtool --include-statistics --show-pause swp0
      Signed-off-by: NVladimir Oltean <vladimir.oltean@nxp.com>
      Signed-off-by: NDavid S. Miller <davem@davemloft.net>
      e32036e1
    • V
      net: dsa: felix: use ocelot's ndo_get_stats64 method · 776b71e5
      Vladimir Oltean 提交于
      Move the logic from the ocelot switchdev driver's ocelot_get_stats64()
      method to the common switch lib and reuse it for the DSA driver.
      Signed-off-by: NVladimir Oltean <vladimir.oltean@nxp.com>
      Signed-off-by: NDavid S. Miller <davem@davemloft.net>
      776b71e5
    • V
      net: dsa: felix: check the 32-bit PSFP stats against overflow · 25027c84
      Vladimir Oltean 提交于
      The Felix PSFP counters suffer from the same problem as the ocelot
      ndo_get_stats64 ones - they are 32-bit, so they can easily overflow and
      this can easily go undetected.
      
      Add a custom hook in ocelot_check_stats_work() through which driver
      specific actions can be taken, and update the stats for the existing
      PSFP filters from that hook.
      
      Previously, vsc9959_psfp_filter_add() and vsc9959_psfp_filter_del() were
      serialized with respect to each other via rtnl_lock(). However, with the
      new entry point into &psfp->sfi_list coming from the periodic worker, we
      now need an explicit mutex to serialize access to these lists.
      
      We used to keep a struct felix_stream_filter_counters on stack, through
      which vsc9959_psfp_stats_get() - a FLOW_CLS_STATS callback - would
      retrieve data from vsc9959_psfp_counters_get(). We need to become
      smarter about that in 3 ways:
      
      - we need to keep a persistent set of counters for each stream instead
        of keeping them on stack
      
      - we need to promote those counters from u32 to u64, and create a
        procedure that properly keeps 64-bit counters. Since we clear the
        hardware counters anyway, and we poll every 2 seconds, a simple
        increment of a u64 counter with a u32 value will perfectly do the job.
      
      - FLOW_CLS_STATS also expect incremental counters, so we also need to
        zeroize our u64 counters every time sch_flower calls us
      Signed-off-by: NVladimir Oltean <vladimir.oltean@nxp.com>
      Signed-off-by: NDavid S. Miller <davem@davemloft.net>
      25027c84
    • V
      net: mscc: ocelot: make access to STAT_VIEW sleepable again · 96980ff7
      Vladimir Oltean 提交于
      To support SPI-controlled switches in the future, access to
      SYS_STAT_CFG_STAT_VIEW needs to be done outside of any spinlock
      protected region, but it still needs to be serialized (by a mutex).
      
      Split the ocelot->stats_lock spinlock into a mutex that serializes
      indirect access to hardware registers (ocelot->stat_view_lock) and a
      spinlock that serializes access to the u64 ocelot->stats array.
      Signed-off-by: NVladimir Oltean <vladimir.oltean@nxp.com>
      Signed-off-by: NDavid S. Miller <davem@davemloft.net>
      96980ff7
    • V
      net: dsa: felix: add definitions for the stream filter counters · 0a2360c5
      Vladimir Oltean 提交于
      TSN stream (802.1Qci, 802.1CB) filters are also accessed through
      STAT_VIEW, just like the port registers, but these counters are per
      stream, rather than per port. So we don't keep them in
      ocelot_port_update_stats().
      
      What we can do, however, is we can create register definitions for them
      just like we have for the port counters, and delete the last remaining
      user of the SYS_CNT register + a group index (read_gix).
      Signed-off-by: NVladimir Oltean <vladimir.oltean@nxp.com>
      Signed-off-by: NDavid S. Miller <davem@davemloft.net>
      0a2360c5
  2. 07 9月, 2022 3 次提交
    • V
      net: dsa: felix: access QSYS_TAG_CONFIG under tas_lock in vsc9959_sched_speed_set · a4bb481a
      Vladimir Oltean 提交于
      The read-modify-write of QSYS_TAG_CONFIG from vsc9959_sched_speed_set()
      runs unlocked with respect to the other functions that access it, which
      are vsc9959_tas_guard_bands_update(), vsc9959_qos_port_tas_set() and
      vsc9959_tas_clock_adjust(). All the others are under ocelot->tas_lock,
      so move the vsc9959_sched_speed_set() access under that lock as well, to
      resolve the concurrency.
      
      Fixes: 55a515b1 ("net: dsa: felix: drop oversized frames with tc-taprio instead of hanging the port")
      Signed-off-by: NVladimir Oltean <vladimir.oltean@nxp.com>
      Signed-off-by: NDavid S. Miller <davem@davemloft.net>
      a4bb481a
    • V
      net: dsa: felix: disable cut-through forwarding for frames oversized for tc-taprio · 843794bb
      Vladimir Oltean 提交于
      Experimentally, it looks like when QSYS_QMAXSDU_CFG_7 is set to 605,
      frames even way larger than 601 octets are transmitted even though these
      should be considered as oversized, according to the documentation, and
      dropped.
      
      Since oversized frame dropping depends on frame size, which is only
      known at the EOF stage, and therefore not at SOF when cut-through
      forwarding begins, it means that the switch cannot take QSYS_QMAXSDU_CFG_*
      into consideration for traffic classes that are cut-through.
      
      Since cut-through forwarding has no UAPI to control it, and the driver
      enables it based on the mantra "if we can, then why not", the strategy
      is to alter vsc9959_cut_through_fwd() to take into consideration which
      tc's have oversize frame dropping enabled, and disable cut-through for
      them. Then, from vsc9959_tas_guard_bands_update(), we re-trigger the
      cut-through determination process.
      
      There are 2 strategies for vsc9959_cut_through_fwd() to determine
      whether a tc has oversized dropping enabled or not. One is to keep a bit
      mask of traffic classes per port, and the other is to read back from the
      hardware registers (a non-zero value of QSYS_QMAXSDU_CFG_* means the
      feature is enabled). We choose reading back from registers, because
      struct ocelot_port is shared with drivers (ocelot, seville) that don't
      support either cut-through nor tc-taprio, and we don't have a felix
      specific extension of struct ocelot_port. Furthermore, reading registers
      from the Felix hardware is quite cheap, since they are memory-mapped.
      
      Fixes: 55a515b1 ("net: dsa: felix: drop oversized frames with tc-taprio instead of hanging the port")
      Signed-off-by: NVladimir Oltean <vladimir.oltean@nxp.com>
      Signed-off-by: NDavid S. Miller <davem@davemloft.net>
      843794bb
    • V
      net: dsa: felix: tc-taprio intervals smaller than MTU should send at least one packet · 11afdc65
      Vladimir Oltean 提交于
      The blamed commit broke tc-taprio schedules such as this one:
      
      tc qdisc replace dev $swp1 root taprio \
              num_tc 8 \
              map 0 1 2 3 4 5 6 7 \
              queues 1@0 1@1 1@2 1@3 1@4 1@5 1@6 1@7 \
              base-time 0 \
              sched-entry S 0x7f 990000 \
              sched-entry S 0x80  10000 \
              flags 0x2
      
      because the gate entry for TC 7 (S 0x80 10000 ns) now has a static guard
      band added earlier than its 'gate close' event, such that packet
      overruns won't occur in the worst case of the largest packet possible.
      
      Since guard bands are statically determined based on the per-tc
      QSYS_QMAXSDU_CFG_* with a fallback on the port-based QSYS_PORT_MAX_SDU,
      we need to discuss what happens with TC 7 depending on kernel version,
      since the driver, prior to commit 55a515b1 ("net: dsa: felix: drop
      oversized frames with tc-taprio instead of hanging the port"), did not
      touch QSYS_QMAXSDU_CFG_*, and therefore relied on QSYS_PORT_MAX_SDU.
      
      1 (before vsc9959_tas_guard_bands_update): QSYS_PORT_MAX_SDU defaults to
        1518, and at gigabit this introduces a static guard band (independent
        of packet sizes) of 12144 ns, plus QSYS::HSCH_MISC_CFG.FRM_ADJ (bit
        time of 20 octets => 160 ns). But this is larger than the time window
        itself, of 10000 ns. So, the queue system never considers a frame with
        TC 7 as eligible for transmission, since the gate practically never
        opens, and these frames are forever stuck in the TX queues and hang
        the port.
      
      2 (after vsc9959_tas_guard_bands_update): Under the sole goal of
        enabling oversized frame dropping, we make an effort to set
        QSYS_QMAXSDU_CFG_7 to 1230 bytes. But QSYS_QMAXSDU_CFG_7 plays
        one more role, which we did not take into account: per-tc static guard
        band, expressed in L2 byte time (auto-adjusted for FCS and L1 overhead).
        There is a discrepancy between what the driver thinks (that there is
        no guard band, and 100% of min_gate_len[tc] is available for egress
        scheduling) and what the hardware actually does (crops the equivalent
        of QSYS_QMAXSDU_CFG_7 ns out of min_gate_len[tc]). In practice, this
        means that the hardware thinks it has exactly 0 ns for scheduling tc 7.
      
      In both cases, even minimum sized Ethernet frames are stuck on egress
      rather than being considered for scheduling on TC 7, even if they would
      fit given a proper configuration. Considering the current situation,
      with vsc9959_tas_guard_bands_update(), frames between 60 octets and 1230
      octets in size are not eligible for oversized dropping (because they are
      smaller than QSYS_QMAXSDU_CFG_7), but won't be considered as eligible
      for scheduling either, because the min_gate_len[7] (10000 ns) minus the
      guard band determined by QSYS_QMAXSDU_CFG_7 (1230 octets * 8 ns per
      octet == 9840 ns) minus the guard band auto-added for L1 overhead by
      QSYS::HSCH_MISC_CFG.FRM_ADJ (20 octets * 8 ns per octet == 160 octets)
      leaves 0 ns for scheduling in the queue system proper.
      
      Investigating the hardware behavior, it becomes apparent that the queue
      system needs precisely 33 ns of 'gate open' time in order to consider a
      frame as eligible for scheduling to a tc. So the solution to this
      problem is to amend vsc9959_tas_guard_bands_update(), by giving the
      per-tc guard bands less space by exactly 33 ns, just enough for one
      frame to be scheduled in that interval. This allows the queue system to
      make forward progress for that port-tc, and prevents it from hanging.
      
      Fixes: 297c4de6 ("net: dsa: felix: re-enable TAS guard band mode")
      Reported-by: NXiaoliang Yang <xiaoliang.yang_1@nxp.com>
      Signed-off-by: NVladimir Oltean <vladimir.oltean@nxp.com>
      Signed-off-by: NDavid S. Miller <davem@davemloft.net>
      11afdc65
  3. 23 8月, 2022 1 次提交
    • V
      net: mscc: ocelot: set up tag_8021q CPU ports independent of user port affinity · 36a0bf44
      Vladimir Oltean 提交于
      This is a partial revert of commit c295f983 ("net: mscc: ocelot:
      switch from {,un}set to {,un}assign for tag_8021q CPU ports"), because
      as it turns out, this isn't how tag_8021q CPU ports under a LAG are
      supposed to work.
      
      Under that scenario, all user ports are "assigned" to the single
      tag_8021q CPU port represented by the logical port corresponding to the
      bonding interface. So one CPU port in a LAG would have is_dsa_8021q_cpu
      set to true (the one whose physical port ID is equal to the logical port
      ID), and the other one to false.
      
      In turn, this makes 2 undesirable things happen:
      
      (1) PGID_CPU contains only the first physical CPU port, rather than both
      (2) only the first CPU port will be added to the private VLANs used by
          ocelot for VLAN-unaware bridging
      
      To make the driver behave in the same way for both bonded CPU ports, we
      need to bring back the old concept of setting up a port as a tag_8021q
      CPU port, and this is what deals with VLAN membership and PGID_CPU
      updating. But we also need the CPU port "assignment" (the user to CPU
      port affinity), and this is what updates the PGID_SRC forwarding rules.
      
      All DSA CPU ports are statically configured for tag_8021q mode when the
      tagging protocol is changed to ocelot-8021q. User ports are "assigned"
      to one CPU port or the other dynamically (this will be handled by a
      future change).
      Signed-off-by: NVladimir Oltean <vladimir.oltean@nxp.com>
      Signed-off-by: NPaolo Abeni <pabeni@redhat.com>
      36a0bf44
  4. 18 8月, 2022 5 次提交
    • V
      net: mscc: ocelot: keep ocelot_stat_layout by reg address, not offset · d4c36765
      Vladimir Oltean 提交于
      With so many counter addresses recently discovered as being wrong, it is
      desirable to at least have a central database of information, rather
      than two: one through the SYS_COUNT_* registers (used for
      ndo_get_stats64), and the other through the offset field of struct
      ocelot_stat_layout elements (used for ethtool -S).
      
      The strategy will be to keep the SYS_COUNT_* definitions as the single
      source of truth, but for that we need to expand our current definitions
      to cover all registers. Then we need to convert the ocelot region
      creation logic, and stats worker, to the read semantics imposed by going
      through SYS_COUNT_* absolute register addresses, rather than offsets
      of 32-bit words relative to SYS_COUNT_RX_OCTETS (which should have been
      SYS_CNT, by the way).
      Signed-off-by: NVladimir Oltean <vladimir.oltean@nxp.com>
      Signed-off-by: NJakub Kicinski <kuba@kernel.org>
      d4c36765
    • V
      net: mscc: ocelot: make struct ocelot_stat_layout array indexable · 91904600
      Vladimir Oltean 提交于
      The ocelot counters are 32-bit and require periodic reading, every 2
      seconds, by ocelot_port_update_stats(), so that wraparounds are
      detected.
      
      Currently, the counters reported by ocelot_get_stats64() come from the
      32-bit hardware counters directly, rather than from the 64-bit
      accumulated ocelot->stats, and this is a problem for their integrity.
      
      The strategy is to make ocelot_get_stats64() able to cherry-pick
      individual stats from ocelot->stats the way in which it currently reads
      them out from SYS_COUNT_* registers. But currently it can't, because
      ocelot->stats is an opaque u64 array that's used only to feed data into
      ethtool -S.
      
      To solve that problem, we need to make ocelot->stats indexable, and
      associate each element with an element of struct ocelot_stat_layout used
      by ethtool -S.
      
      This makes ocelot_stat_layout a fat (and possibly sparse) array, so we
      need to change the way in which we access it. We no longer need
      OCELOT_STAT_END as a sentinel, because we know the array's size
      (OCELOT_NUM_STATS). We just need to skip the array elements that were
      left unpopulated for the switch revision (ocelot, felix, seville).
      Signed-off-by: NVladimir Oltean <vladimir.oltean@nxp.com>
      Signed-off-by: NJakub Kicinski <kuba@kernel.org>
      91904600
    • V
      net: mscc: ocelot: turn stats_lock into a spinlock · 22d842e3
      Vladimir Oltean 提交于
      ocelot_get_stats64() currently runs unlocked and therefore may collide
      with ocelot_port_update_stats() which indirectly accesses the same
      counters. However, ocelot_get_stats64() runs in atomic context, and we
      cannot simply take the sleepable ocelot->stats_lock mutex. We need to
      convert it to an atomic spinlock first. Do that as a preparatory change.
      Signed-off-by: NVladimir Oltean <vladimir.oltean@nxp.com>
      Signed-off-by: NJakub Kicinski <kuba@kernel.org>
      22d842e3
    • V
      net: mscc: ocelot: fix incorrect ndo_get_stats64 packet counters · 5152de7b
      Vladimir Oltean 提交于
      Reading stats using the SYS_COUNT_* register definitions is only used by
      ocelot_get_stats64() from the ocelot switchdev driver, however,
      currently the bucket definitions are incorrect.
      
      Separately, on both RX and TX, we have the following problems:
      - a 256-1023 bucket which actually tracks the 256-511 packets
      - the 1024-1526 bucket actually tracks the 512-1023 packets
      - the 1527-max bucket actually tracks the 1024-1526 packets
      
      => nobody tracks the packets from the real 1527-max bucket
      
      Additionally, the RX_PAUSE, RX_CONTROL, RX_LONGS and RX_CLASSIFIED_DROPS
      all track the wrong thing. However this doesn't seem to have any
      consequence, since ocelot_get_stats64() doesn't use these.
      
      Even though this problem only manifests itself for the switchdev driver,
      we cannot split the fix for ocelot and for DSA, since it requires fixing
      the bucket definitions from enum ocelot_reg, which makes us necessarily
      adapt the structures from felix and seville as well.
      
      Fixes: 84705fc1 ("net: dsa: felix: introduce support for Seville VSC9953 switch")
      Fixes: 56051948 ("net: dsa: ocelot: add driver for Felix switch family")
      Fixes: a556c76a ("net: mscc: Add initial Ocelot switch support")
      Signed-off-by: NVladimir Oltean <vladimir.oltean@nxp.com>
      Signed-off-by: NJakub Kicinski <kuba@kernel.org>
      5152de7b
    • V
      net: dsa: felix: fix ethtool 256-511 and 512-1023 TX packet counters · 40d21c45
      Vladimir Oltean 提交于
      What the driver actually reports as 256-511 is in fact 512-1023, and the
      TX packets in the 256-511 bucket are not reported. Fix that.
      
      Fixes: 56051948 ("net: dsa: ocelot: add driver for Felix switch family")
      Signed-off-by: NVladimir Oltean <vladimir.oltean@nxp.com>
      Signed-off-by: NJakub Kicinski <kuba@kernel.org>
      40d21c45
  5. 10 8月, 2022 1 次提交
    • V
      net: dsa: felix: suppress non-changes to the tagging protocol · 4c46bb49
      Vladimir Oltean 提交于
      The way in which dsa_tree_change_tag_proto() works is that when
      dsa_tree_notify() fails, it doesn't know whether the operation failed
      mid way in a multi-switch tree, or it failed for a single-switch tree.
      So even though drivers need to fail cleanly in
      ds->ops->change_tag_protocol(), DSA will still call dsa_tree_notify()
      again, to restore the old tag protocol for potential switches in the
      tree where the change did succeeed (before failing for others).
      
      This means for the felix driver that if we report an error in
      felix_change_tag_protocol(), we'll get another call where proto_ops ==
      old_proto_ops. If we proceed to act upon that, we may do unexpected
      things. For example, we will call dsa_tag_8021q_register() twice in a
      row, without any dsa_tag_8021q_unregister() in between. Then we will
      actually call dsa_tag_8021q_unregister() via old_proto_ops->teardown,
      which (if it manages to run at all, after walking through corrupted data
      structures) will leave the ports inoperational anyway.
      
      The bug can be readily reproduced if we force an error while in
      tag_8021q mode; this crashes the kernel.
      
      echo ocelot-8021q > /sys/class/net/eno2/dsa/tagging
      echo edsa > /sys/class/net/eno2/dsa/tagging # -EPROTONOSUPPORT
      
      Unable to handle kernel NULL pointer dereference at virtual address 0000000000000014
      Call trace:
       vcap_entry_get+0x24/0x124
       ocelot_vcap_filter_del+0x198/0x270
       felix_tag_8021q_vlan_del+0xd4/0x21c
       dsa_switch_tag_8021q_vlan_del+0x168/0x2cc
       dsa_switch_event+0x68/0x1170
       dsa_tree_notify+0x14/0x34
       dsa_port_tag_8021q_vlan_del+0x84/0x110
       dsa_tag_8021q_unregister+0x15c/0x1c0
       felix_tag_8021q_teardown+0x16c/0x180
       felix_change_tag_protocol+0x1bc/0x230
       dsa_switch_event+0x14c/0x1170
       dsa_tree_change_tag_proto+0x118/0x1c0
      
      Fixes: 7a29d220 ("net: dsa: felix: reimplement tagging protocol change with function pointers")
      Signed-off-by: NVladimir Oltean <vladimir.oltean@nxp.com>
      Reviewed-by: NFlorian Fainelli <f.fainelli@gmail.com>
      Link: https://lore.kernel.org/r/20220808125127.3344094-1-vladimir.oltean@nxp.comSigned-off-by: NJakub Kicinski <kuba@kernel.org>
      4c46bb49
  6. 09 8月, 2022 1 次提交
    • V
      net: dsa: felix: fix min gate len calculation for tc when its first gate is closed · 7e4babff
      Vladimir Oltean 提交于
      min_gate_len[tc] is supposed to track the shortest interval of
      continuously open gates for a traffic class. For example, in the
      following case:
      
      TC 76543210
      
      t0 00000001b 200000 ns
      t1 00000010b 200000 ns
      
      min_gate_len[0] and min_gate_len[1] should be 200000, while
      min_gate_len[2-7] should be 0.
      
      However what happens is that min_gate_len[0] is 200000, but
      min_gate_len[1] ends up being 0 (despite gate_len[1] being 200000 at the
      point where the logic detects the gate close event for TC 1).
      
      The problem is that the code considers a "gate close" event whenever it
      sees that there is a 0 for that TC (essentially it's level rather than
      edge triggered). By doing that, any time a gate is seen as closed
      without having been open prior, gate_len, which is 0, will be written
      into min_gate_len. Once min_gate_len becomes 0, it's impossible for it
      to track anything higher than that (the length of actually open
      intervals).
      
      To fix this, we make the writing to min_gate_len[tc] be edge-triggered,
      which avoids writes for gates that are closed in consecutive intervals.
      However what this does is it makes us need to special-case the
      permanently closed gates at the end.
      
      Fixes: 55a515b1 ("net: dsa: felix: drop oversized frames with tc-taprio instead of hanging the port")
      Signed-off-by: NVladimir Oltean <vladimir.oltean@nxp.com>
      Link: https://lore.kernel.org/r/20220804202817.1677572-1-vladimir.oltean@nxp.comSigned-off-by: NJakub Kicinski <kuba@kernel.org>
      7e4babff
  7. 06 7月, 2022 1 次提交
  8. 01 7月, 2022 5 次提交
    • V
      time64.h: consolidate uses of PSEC_PER_NSEC · 837ced3a
      Vladimir Oltean 提交于
      Time-sensitive networking code needs to work with PTP times expressed in
      nanoseconds, and with packet transmission times expressed in
      picoseconds, since those would be fractional at higher than gigabit
      speed when expressed in nanoseconds.
      
      Convert the existing uses in tc-taprio and the ocelot/felix DSA driver
      to a PSEC_PER_NSEC macro. This macro is placed in include/linux/time64.h
      as opposed to its relatives (PSEC_PER_SEC etc) from include/vdso/time64.h
      because the vDSO library does not (yet) need/use it.
      
      Cc: Andy Lutomirski <luto@kernel.org>
      Cc: Thomas Gleixner <tglx@linutronix.de>
      Signed-off-by: NVladimir Oltean <vladimir.oltean@nxp.com>
      Reviewed-by: Vincenzo Frascino <vincenzo.frascino@arm.com> # for the vDSO parts
      Signed-off-by: NJakub Kicinski <kuba@kernel.org>
      837ced3a
    • V
      net: dsa: felix: drop oversized frames with tc-taprio instead of hanging the port · 55a515b1
      Vladimir Oltean 提交于
      Currently, sending a packet into a time gate too small for it (or always
      closed) causes the queue system to hold the frame forever. Even worse,
      this frame isn't subject to aging either, because for that to happen, it
      needs to be scheduled for transmission in the first place. But the frame
      will consume buffer memory and frame references while it is forever held
      in the queue system.
      
      Before commit a4ae997a ("net: mscc: ocelot: initialize watermarks to
      sane defaults"), this behavior was somewhat subtle, as the switch had a
      more intricately tuned default watermark configuration out of reset,
      which did not allow any single port and tc to consume the entire switch
      buffer space. Nonetheless, the held frames are still there, and they
      reduce the total backplane capacity of the switch.
      
      However, after the aforementioned commit, the behavior can be very
      clearly seen, since we deliberately allow each {port, tc} to consume the
      entire shared buffer of the switch minus the reservations (and we
      disable all reservations by default). That is to say, we allow a
      permanently closed tc-taprio gate to hang the entire switch.
      
      A careful inspection of the documentation shows that the QSYS:Q_MAX_SDU
      per-port-tc registers serve 2 purposes: one is for guard band calculation
      (when zero, this falls back to QSYS:PORT_MAX_SDU), and the other is to
      enable oversized frame dropping (when non-zero).
      
      Currently the QSYS:Q_MAX_SDU registers are all zero, so oversized frame
      dropping is disabled. The goal of the change is to enable it seamlessly.
      For that, we need to hook into the MTU change, tc-taprio change, and
      port link speed change procedures, since we depend on these variables.
      
      Frames are not dropped on egress due to a queue system oversize
      condition, instead that egress port is simply excluded from the mask of
      valid destination ports for the packet. If there are no destination
      ports at all, the ingress counter that increments is the generic
      "drop_tail" in ethtool -S.
      
      The issue exists in various forms since the tc-taprio offload was introduced.
      
      Fixes: de143c0e ("net: dsa: felix: Configure Time-Aware Scheduler via taprio offload")
      Reported-by: NRichie Pearn <richard.pearn@nxp.com>
      Signed-off-by: NVladimir Oltean <vladimir.oltean@nxp.com>
      Signed-off-by: NJakub Kicinski <kuba@kernel.org>
      55a515b1
    • V
      net: dsa: felix: keep QSYS_TAG_CONFIG_INIT_GATE_STATE(0xFF) out of rmw · d68a373b
      Vladimir Oltean 提交于
      In vsc9959_tas_clock_adjust(), the INIT_GATE_STATE field is not changed,
      only the ENABLE field. Similarly for the disabling of the time-aware
      shaper in vsc9959_qos_port_tas_set().
      
      To reflect this, keep the QSYS_TAG_CONFIG_INIT_GATE_STATE_M mask out of
      the read-modify-write procedure to make it clearer what is the intention
      of the code.
      Signed-off-by: NVladimir Oltean <vladimir.oltean@nxp.com>
      Signed-off-by: NJakub Kicinski <kuba@kernel.org>
      d68a373b
    • V
      net: dsa: felix: keep reference on entire tc-taprio config · 1c9017e4
      Vladimir Oltean 提交于
      In a future change we will need to remember the entire tc-taprio config
      on all ports rather than just the base time, so use the
      taprio_offload_get() helper function to replace ocelot_port->base_time
      with ocelot_port->taprio.
      Signed-off-by: NVladimir Oltean <vladimir.oltean@nxp.com>
      Signed-off-by: NJakub Kicinski <kuba@kernel.org>
      1c9017e4
    • V
      net: dsa: felix: fix race between reading PSFP stats and port stats · 58bf4db6
      Vladimir Oltean 提交于
      Both PSFP stats and the port stats read by ocelot_check_stats_work() are
      indirectly read through the same mechanism - write to STAT_CFG:STAT_VIEW,
      read from SYS:STAT:CNT[n].
      
      It's just that for port stats, we write STAT_VIEW with the index of the
      port, and for PSFP stats, we write STAT_VIEW with the filter index.
      
      So if we allow them to run concurrently, ocelot_check_stats_work() may
      change the view from vsc9959_psfp_counters_get(), and vice versa.
      
      Fixes: 7d4b564d ("net: dsa: felix: support psfp filter on vsc9959")
      Signed-off-by: NVladimir Oltean <vladimir.oltean@nxp.com>
      Link: https://lore.kernel.org/r/20220629183007.3808130-1-vladimir.oltean@nxp.comSigned-off-by: NJakub Kicinski <kuba@kernel.org>
      58bf4db6
  9. 19 6月, 2022 1 次提交
    • X
      net: dsa: felix: update base time of time-aware shaper when adjusting PTP time · 8670dc33
      Xiaoliang Yang 提交于
      When adjusting the PTP clock, the base time of the TAS configuration
      will become unreliable. We need reset the TAS configuration by using a
      new base time.
      
      For example, if the driver gets a base time 0 of Qbv configuration from
      user, and current time is 20000. The driver will set the TAS base time
      to be 20000. After the PTP clock adjustment, the current time becomes
      10000. If the TAS base time is still 20000, it will be a future time,
      and TAS entry list will stop running. Another example, if the current
      time becomes to be 10000000 after PTP clock adjust, a large time offset
      can cause the hardware to hang.
      
      This patch introduces a tas_clock_adjust() function to reset the TAS
      module by using a new base time after the PTP clock adjustment. This can
      avoid issues above.
      
      Due to PTP clock adjustment can occur at any time, it may conflict with
      the TAS configuration. We introduce a new TAS lock to serialize the
      access to the TAS registers.
      Signed-off-by: NXiaoliang Yang <xiaoliang.yang_1@nxp.com>
      Signed-off-by: NDavid S. Miller <davem@davemloft.net>
      8670dc33
  10. 23 5月, 2022 6 次提交
    • V
      net: dsa: felix: tag_8021q preparation for multiple CPU ports · a4e044dc
      Vladimir Oltean 提交于
      Update the VCAP filters to support multiple tag_8021q CPU ports.
      
      TX works using a filter for VLAN ID on the ingress of the CPU port, with
      a redirect and a VLAN pop action. This can be updated trivially by
      amending the ingress port mask of this rule to match on all tag_8021q
      CPU ports.
      
      RX works using a filter for ingress port on the egress of the CPU port,
      with a VLAN push action. Here we need to replicate these filters for
      each tag_8021q CPU port, and let them all have the same action.
      This means that the OCELOT_VCAP_ES0_TAG_8021Q_RXVLAN() cookie needs to
      encode a unique value for every {user port, CPU port} pair it's given.
      Do this by encoding the CPU port in the upper 16 bits of the cookie, and
      the user port in the lower 16 bits.
      Signed-off-by: NVladimir Oltean <vladimir.oltean@nxp.com>
      Signed-off-by: NDavid S. Miller <davem@davemloft.net>
      a4e044dc
    • V
      net: mscc: ocelot: switch from {,un}set to {,un}assign for tag_8021q CPU ports · c295f983
      Vladimir Oltean 提交于
      There is a desire for the felix driver to gain support for multiple
      tag_8021q CPU ports, but the current model prevents it.
      
      This is because ocelot_apply_bridge_fwd_mask() only takes into
      consideration whether a port is a tag_8021q CPU port, but not whose CPU
      port it is.
      
      We need a model where we can have a direct affinity between an ocelot
      port and a tag_8021q CPU port. This serves as the basis for multiple CPU
      ports.
      
      Declare a "dsa_8021q_cpu" backpointer in struct ocelot_port which
      encodes that affinity. Repurpose the "ocelot_set_dsa_8021q_cpu" API to
      "ocelot_assign_dsa_8021q_cpu" to express the change of paradigm.
      
      Note that this change makes the first practical use of the new
      ocelot_port->index field in ocelot_port_unassign_dsa_8021q_cpu(), where
      we need to remove the old tag_8021q CPU port from the reserved VLAN range.
      Signed-off-by: NVladimir Oltean <vladimir.oltean@nxp.com>
      Signed-off-by: NDavid S. Miller <davem@davemloft.net>
      c295f983
    • V
      net: dsa: felix: directly call ocelot_port_{set,unset}_dsa_8021q_cpu · 8c166acb
      Vladimir Oltean 提交于
      Absorb the final details of calling ocelot_port_{,un}set_dsa_8021q_cpu(),
      i.e. the need to lock &ocelot->fwd_domain_lock, into the callee, to
      simplify the caller and permit easier code reuse later.
      Signed-off-by: NVladimir Oltean <vladimir.oltean@nxp.com>
      Signed-off-by: NDavid S. Miller <davem@davemloft.net>
      8c166acb
    • V
      net: dsa: felix: update bridge fwd mask from ocelot lib when changing tag_8021q CPU · a72e23dd
      Vladimir Oltean 提交于
      Add more logic to ocelot_port_{,un}set_dsa_8021q_cpu() from the ocelot
      switch lib by encapsulating the ocelot_apply_bridge_fwd_mask() call that
      felix used to have.
      
      This is necessary because the CPU port change procedure will also need
      to do this, and it's good to reduce code duplication by having an entry
      point in the ocelot switch lib that does all that is needed.
      Signed-off-by: NVladimir Oltean <vladimir.oltean@nxp.com>
      Signed-off-by: NDavid S. Miller <davem@davemloft.net>
      a72e23dd
    • V
      net: dsa: felix: move the updating of PGID_CPU to the ocelot lib · 61be79ba
      Vladimir Oltean 提交于
      PGID_CPU must be updated every time a port is configured or unconfigured
      as a tag_8021q CPU port. The ocelot switch lib already has a hook for
      that operation, so move the updating of PGID_CPU to those hooks.
      
      These bits are pretty specific to DSA, so normally I would keep them out
      of the common switch lib, but when tag_8021q is in use, this has
      implications upon the forwarding mask determined by
      ocelot_apply_bridge_fwd_mask() and called extensively by the switch lib.
      Signed-off-by: NVladimir Oltean <vladimir.oltean@nxp.com>
      Signed-off-by: NDavid S. Miller <davem@davemloft.net>
      61be79ba
    • V
      net: dsa: fix missing adjustment of host broadcast flooding · 129b7532
      Vladimir Oltean 提交于
      PGID_BC is configured statically by ocelot_init() to flood towards the
      CPU port module, and dynamically by ocelot_port_set_bcast_flood()
      towards all user ports.
      
      When the tagging protocol changes, the intention is to turn off flooding
      towards the old pipe towards the host, and to turn it on towards the new
      pipe.
      
      Due to a recent change which removed the adjustment of PGID_BC from
      felix_set_host_flood(), 3 things happen.
      
      - when we change from NPI to tag_8021q mode: in this mode, the CPU port
        module is accessed via registers, and used to read PTP packets with
        timestamps. We fail to disable broadcast flooding towards the CPU port
        module, and to enable broadcast flooding towards the physical port
        that serves as a DSA tag_8021q CPU port.
      
      - from tag_8021q to NPI mode: in this mode, the CPU port module is
        redirected to a physical port. We fail to disable broadcast flooding
        towards the physical tag_8021q CPU port, and to enable it towards the
        CPU port module at ocelot->num_phys_ports.
      
      - when the ports are put in promiscuous mode, we also fail to update
        PGID_BC towards the host pipe of the current protocol.
      
      First issue means that felix_check_xtr_pkt() has to do extra work,
      because it will not see only PTP packets, but also broadcasts. It needs
      to dequeue these packets just to drop them.
      
      Third issue is inconsequential, since PGID_BC is allocated from the
      nonreserved multicast PGID space, and these PGIDs are conveniently
      initialized to 0x7f (i.e. flood towards all ports except the CPU port
      module). Broadcasts reach the NPI port via ocelot_init(), and reach the
      tag_8021q CPU port via the hardware defaults.
      
      Second issue is also inconsequential, because we fail both at disabling
      and at enabling broadcast flooding on a port, so the defaults mentioned
      above are preserved, and they are fine except for the performance impact.
      
      Fixes: 7a29d220 ("net: dsa: felix: reimplement tagging protocol change with function pointers")
      Signed-off-by: NVladimir Oltean <vladimir.oltean@nxp.com>
      Signed-off-by: NDavid S. Miller <davem@davemloft.net>
      129b7532
  11. 13 5月, 2022 8 次提交
    • V
      net: mscc: ocelot: move ocelot_port_private :: chip_port to ocelot_port :: index · 7e708760
      Vladimir Oltean 提交于
      Currently the ocelot switch lib is unaware of the index of a struct
      ocelot_port, since that is kept in the encapsulating structures of outer
      drivers (struct dsa_port :: index, struct ocelot_port_private :: chip_port).
      
      With the upcoming increase in complexity associated with assigning DSA
      tag_8021q CPU ports to certain user ports, it becomes necessary for the
      switch lib to be able to retrieve the index of a certain ocelot_port.
      
      Therefore, introduce a new u8 to ocelot_port (same size as the chip_port
      used by the ocelot switchdev driver) and rework the existing code to
      populate and use it.
      Signed-off-by: NVladimir Oltean <vladimir.oltean@nxp.com>
      Signed-off-by: NJakub Kicinski <kuba@kernel.org>
      7e708760
    • V
      net: dsa: felix: reimplement tagging protocol change with function pointers · 7a29d220
      Vladimir Oltean 提交于
      The error handling for the current tagging protocol change procedure is
      a bit brittle (we dismantle the previous tagging protocol entirely
      before setting up the new one). By identifying which parts of a tagging
      protocol are unique to itself and which parts are shared with the other,
      we can implement a protocol change procedure where error handling is a
      bit more robust, because we start setting up the new protocol first, and
      tear down the old one only after the setup of the specific and shared
      parts succeeded.
      
      The protocol change is a bit too open-coded too, in the area of
      migrating host flood settings and MDBs. By identifying what differs
      between tagging protocols (the forwarding masks for host flooding) we
      can implement a more straightforward migration procedure which is
      handled in the shared portion of the protocol change, rather than
      individually by each protocol.
      
      Therefore, a more structured approach calls for the introduction of a
      structure of function pointers per tagging protocol. This covers setup,
      teardown and the host forwarding mask. In the future it will also cover
      how to prepare for a new DSA master.
      
      The initial tagging protocol setup (at driver probe time) and the final
      teardown (at driver removal time) are also adapted to call into the
      structured methods of the specific protocol in current use. This is
      especially relevant for teardown, where we previously called
      felix_del_tag_protocol() only for the first CPU port. But by not
      specifying which CPU port this is for, we gain more flexibility to
      support multiple CPU ports in the future.
      Signed-off-by: NVladimir Oltean <vladimir.oltean@nxp.com>
      Signed-off-by: NJakub Kicinski <kuba@kernel.org>
      7a29d220
    • V
      net: dsa: felix: dynamically determine tag_8021q CPU port for traps · c352e5e8
      Vladimir Oltean 提交于
      Ocelot switches support a single active CPU port at a time (at least as
      a trapping destination, i.e. for control traffic). This is true
      regardless of whether we are using the native copy-to-CPU-port-module
      functionality, or a redirect action towards the software-defined
      tag_8021q CPU port.
      
      Currently we assume that the trapping destination in tag_8021q mode is
      the first CPU port, yet in the future we may want to migrate the user
      ports to the second CPU port.
      
      For that to work, we need to make sure that the tag_8021q trapping
      destination is a CPU port that is active, i.e. is used by at least some
      user port on which the trap was added. Otherwise, we may end up
      redirecting the traffic to a CPU port which isn't even up.
      
      Note that due to the current design where we simply choose the CPU port
      of the first port from the trap's ingress port mask, it may be that a
      CPU port absorbes control traffic from user ports which aren't affine to
      it as per user space's request. This isn't ideal, but is the lesser of
      two evils. Following the user-configured affinity for traps would mean
      that we can no longer reuse a single TCAM entry for multiple traps,
      which is what we actually do for e.g. PTP. Either we duplicate and
      deduplicate TCAM entries on the fly when user-to-CPU-port mappings
      change (which is unnecessarily complicated), or we redirect trapped
      traffic to all tag_8021q CPU ports if multiple such ports are in use.
      The latter would have actually been nice, if it actually worked, but it
      doesn't, since a OCELOT_MASK_MODE_REDIRECT action towards multiple ports
      would not take PGID_SRC into consideration, and it would just duplicate
      the packet towards each (CPU) port, leading to duplicates in software.
      Signed-off-by: NVladimir Oltean <vladimir.oltean@nxp.com>
      Signed-off-by: NJakub Kicinski <kuba@kernel.org>
      c352e5e8
    • V
      net: dsa: remove port argument from ->change_tag_protocol() · bacf93b0
      Vladimir Oltean 提交于
      DSA has not supported (and probably will not support in the future
      either) independent tagging protocols per CPU port.
      
      Different switch drivers have different requirements, some may need to
      replicate some settings for each CPU port, some may need to apply some
      settings on a single CPU port, while some may have to configure some
      global settings and then some per-CPU-port settings.
      
      In any case, the current model where DSA calls ->change_tag_protocol for
      each CPU port turns out to be impractical for drivers where there are
      global things to be done. For example, felix calls dsa_tag_8021q_register(),
      which makes no sense per CPU port, so it suppresses the second call.
      
      Let drivers deal with replication towards all CPU ports, and remove the
      CPU port argument from the function prototype.
      Signed-off-by: NVladimir Oltean <vladimir.oltean@nxp.com>
      Acked-by: NLuiz Angelo Daros de Luca <luizluca@gmail.com>
      Signed-off-by: NJakub Kicinski <kuba@kernel.org>
      bacf93b0
    • V
      net: dsa: felix: manage host flooding using a specific driver callback · 72c3b0c7
      Vladimir Oltean 提交于
      At the time - commit 7569459a ("net: dsa: manage flooding on the CPU
      ports") - not introducing a dedicated switch callback for host flooding
      made sense, because for the only user, the felix driver, there was
      nothing different to do for the CPU port than set the flood flags on the
      CPU port just like on any other bridge port.
      
      There are 2 reasons why this approach is not good enough, however.
      
      (1) Other drivers, like sja1105, support configuring flooding as a
          function of {ingress port, egress port}, whereas the DSA
          ->port_bridge_flags() function only operates on an egress port.
          So with that driver we'd have useless host flooding from user ports
          which don't need it.
      
      (2) Even with the felix driver, support for multiple CPU ports makes it
          difficult to piggyback on ->port_bridge_flags(). The way in which
          the felix driver is going to support host-filtered addresses with
          multiple CPU ports is that it will direct these addresses towards
          both CPU ports (in a sort of multicast fashion), then restrict the
          forwarding to only one of the two using the forwarding masks.
          Consequently, flooding will also be enabled towards both CPU ports.
          However, ->port_bridge_flags() gets passed the index of a single CPU
          port, and that leaves the flood settings out of sync between the 2
          CPU ports.
      
      This is to say, it's better to have a specific driver method for host
      flooding, which takes the user port as argument. This solves problem (1)
      by allowing the driver to do different things for different user ports,
      and problem (2) by abstracting the operation and letting the driver do
      whatever, rather than explicitly making the DSA core point to the CPU
      port it thinks needs to be touched.
      
      This new method also creates a problem, which is that cross-chip setups
      are not handled. However I don't have hardware right now where I can
      test what is the proper thing to do, and there isn't hardware compatible
      with multi-switch trees that supports host flooding. So it remains a
      problem to be tackled in the future.
      Signed-off-by: NVladimir Oltean <vladimir.oltean@nxp.com>
      Signed-off-by: NJakub Kicinski <kuba@kernel.org>
      72c3b0c7
    • V
      net: dsa: felix: bring the NPI port indirection for host flooding to surface · 910ee6cc
      Vladimir Oltean 提交于
      For symmetry with host FDBs and MDBs where the indirection is now
      handled outside the ocelot switch lib, do the same for bridge port
      flags (unicast/multicast/broadcast flooding).
      
      The only caller of the ocelot switch lib which uses the NPI port is the
      Felix DSA driver.
      Signed-off-by: NVladimir Oltean <vladimir.oltean@nxp.com>
      Signed-off-by: NJakub Kicinski <kuba@kernel.org>
      910ee6cc
    • V
      net: dsa: felix: bring the NPI port indirection for host MDBs to surface · 0ddf83cd
      Vladimir Oltean 提交于
      For symmetry with host FDBs where the indirection is now handled outside
      the ocelot switch lib, do the same for host MDB entries. The only caller
      of the ocelot switch lib which uses the NPI port is the Felix DSA driver.
      Signed-off-by: NVladimir Oltean <vladimir.oltean@nxp.com>
      Signed-off-by: NJakub Kicinski <kuba@kernel.org>
      0ddf83cd
    • V
      net: dsa: felix: program host FDB entries towards PGID_CPU for tag_8021q too · e9b3ba43
      Vladimir Oltean 提交于
      I remembered why we had the host FDB migration procedure in place.
      
      It is true that host FDB entry migration can be done by changing the
      value of PGID_CPU, but the problem is that only host FDB entries learned
      while operating in NPI mode go to PGID_CPU. When the CPU port operates
      in tag_8021q mode, the FDB entries are learned towards the unicast PGID
      equal to the physical port number of this CPU port, bypassing the
      PGID_CPU indirection.
      
      So host FDB entries learned in tag_8021q mode are not migrated any
      longer towards the NPI port.
      
      Fix this by extracting the NPI port -> PGID_CPU redirection from the
      ocelot switch lib, moving it to the Felix DSA driver, and applying it
      for any CPU port regardless of its kind (NPI or tag_8021q).
      
      Fixes: a51c1c3f ("net: dsa: felix: stop migrating FDBs back and forth on tag proto change")
      Signed-off-by: NVladimir Oltean <vladimir.oltean@nxp.com>
      Signed-off-by: NJakub Kicinski <kuba@kernel.org>
      e9b3ba43
  12. 12 5月, 2022 1 次提交