Merge branch 'add-ppe-driver-for-qualcomm-ipq9574-soc'

Luo Jie says:

====================
Add PPE driver for Qualcomm IPQ9574 SoC

The PPE (packet process engine) hardware block is available in Qualcomm
IPQ chipsets that support PPE architecture, such as IPQ9574 and IPQ5332.
The PPE in the IPQ9574 SoC includes six Ethernet ports (6 GMAC and 6
XGMAC), which are used to connect with external PHY devices by PCS. The
PPE also includes packet processing offload capabilities for various
networking functions such as route and bridge flows, VLANs, different
tunnel protocols and VPN. It also includes an L2 switch function for
bridging packets among the 6 Ethernet ports and the CPU port. The CPU
port enables packet transfer between the Ethernet ports and the ARM
cores in the SoC, using the Ethernet DMA.

This patch series is the first part of a three part series that will
together enable Ethernet function for IPQ9574 SoC. While support is
initially being added for IPQ9574 SoC, the driver will be easily
extendable to enable Ethernet support for other IPQ SoC such as IPQ5332.
The driver can also be extended later for adding support for L2/L3
network offload features that the PPE can support. The functionality
to be enabled by each of the three series (to be posted sequentially)
is as below:

Part 1: The PPE patch series (this series), which enables the platform
driver, probe and initialization/configuration of different PPE hardware
blocks.

Part 2: The PPE MAC patch series, which enables the phylink operations
for the PPE Ethernet ports.

Part 3: The PPE EDMA patch series, which enables the Rx/Tx Ethernet DMA
and netdevice driver for the 6 PPE Ethernet ports.

A more detailed description of the functions enabled by part 1 is below:
1. Initialize PPE device hardware functions such as buffer management,
   queue management, scheduler and clocks in order to bring up PPE
   device.
2. Enable platform driver and probe functions
3. Register debugfs file to provide access to various PPE packet
   counters. These statistics are recorded by the various hardware
   process counters, such as port RX/TX, CPU code and hardware queue
   counters.
4. A detailed introduction of PPE along with the PPE hardware diagram
   in the first two patches (dt-bindings and documentation).

Below is a reference to an earlier RFC discussion with the community
about enabling Ethernet driver support for Qualcomm IPQ9574 SoC. This
writeup can help provide a higher level architectural view of various
other drivers that support the PPE such as clock and PCS drivers.
Topic: RFC: Advice on adding support for Qualcomm IPQ9574 SoC Ethernet.
https://lore.kernel.org/linux-arm-msm/d2929bd2-bc9e-4733-a89f-2a187e8bf917@quicinc.com/

Signed-off-by: Luo Jie <quic_luoj@quicinc.com>
====================

Link: https://patch.msgid.link/20250818-qcom_ipq_ppe-v8-0-1d4ff641fce9@quicinc.com
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
This commit is contained in:
Paolo Abeni 2025-08-21 12:38:43 +02:00
commit ae76e8d2c2
14 changed files with 4842 additions and 0 deletions

View File

@ -0,0 +1,533 @@
# SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause
%YAML 1.2
---
$id: http://devicetree.org/schemas/net/qcom,ipq9574-ppe.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Qualcomm IPQ packet process engine (PPE)
maintainers:
- Luo Jie <quic_luoj@quicinc.com>
- Lei Wei <quic_leiwei@quicinc.com>
- Suruchi Agarwal <quic_suruchia@quicinc.com>
- Pavithra R <quic_pavir@quicinc.com>
description: |
The Ethernet functionality in the PPE (Packet Process Engine) is comprised
of three components, the switch core, port wrapper and Ethernet DMA.
The Switch core in the IPQ9574 PPE has maximum of 6 front panel ports and
two FIFO interfaces. One of the two FIFO interfaces is used for Ethernet
port to host CPU communication using Ethernet DMA. The other is used
communicating to the EIP engine which is used for IPsec offload. On the
IPQ9574, the PPE includes 6 GMAC/XGMACs that can be connected with external
Ethernet PHY. Switch core also includes BM (Buffer Management), QM (Queue
Management) and SCH (Scheduler) modules for supporting the packet processing.
The port wrapper provides connections from the 6 GMAC/XGMACS to UNIPHY (PCS)
supporting various modes such as SGMII/QSGMII/PSGMII/USXGMII/10G-BASER. There
are 3 UNIPHY (PCS) instances supported on the IPQ9574.
Ethernet DMA is used to transmit and receive packets between the six Ethernet
ports and ARM host CPU.
The follow diagram shows the PPE hardware block along with its connectivity
to the external hardware blocks such clock hardware blocks (CMNPLL, GCC,
NSS clock controller) and Ethernet PCS/PHY blocks. For depicting the PHY
connectivity, one 4x1 Gbps PHY (QCA8075) and two 10 GBps PHYs are used as an
example.
+---------+
| 48 MHZ |
+----+----+
|(clock)
v
+----+----+
+------| CMN PLL |
| +----+----+
| |(clock)
| v
| +----+----+ +----+----+ (clock) +----+----+
| +---| NSSCC | | GCC |--------->| MDIO |
| | +----+----+ +----+----+ +----+----+
| | |(clock & reset) |(clock)
| | v v
| | +----+---------------------+--+----------+----------+---------+
| | | +-----+ |EDMA FIFO | | EIP FIFO|
| | | | SCH | +----------+ +---------+
| | | +-----+ | | |
| | | +------+ +------+ +-------------------+ |
| | | | BM | | QM | IPQ9574-PPE | L2/L3 Process | |
| | | +------+ +------+ +-------------------+ |
| | | | |
| | | +-------+ +-------+ +-------+ +-------+ +-------+ +-------+ |
| | | | MAC0 | | MAC1 | | MAC2 | | MAC3 | | XGMAC4| |XGMAC5 | |
| | | +---+---+ +---+---+ +---+---+ +---+---+ +---+---+ +---+---+ |
| | | | | | | | | |
| | +-----+---------+---------+---------+---------+---------+-----+
| | | | | | | |
| | +---+---------+---------+---------+---+ +---+---+ +---+---+
+--+---->| PCS0 | | PCS1 | | PCS2 |
|(clock) +---+---------+---------+---------+---+ +---+---+ +---+---+
| | | | | | |
| +---+---------+---------+---------+---+ +---+---+ +---+---+
+------->| QCA8075 PHY | | PHY4 | | PHY5 |
(clock) +-------------------------------------+ +-------+ +-------+
properties:
compatible:
enum:
- qcom,ipq9574-ppe
reg:
maxItems: 1
clocks:
items:
- description: PPE core clock
- description: PPE APB (Advanced Peripheral Bus) clock
- description: PPE IPE (Ingress Process Engine) clock
- description: PPE BM, QM and scheduler clock
clock-names:
items:
- const: ppe
- const: apb
- const: ipe
- const: btq
resets:
maxItems: 1
description: PPE reset, which is necessary before configuring PPE hardware
interrupts:
maxItems: 1
description: PPE switch miscellaneous interrupt
interconnects:
items:
- description: Bus interconnect path leading to PPE switch core function
- description: Bus interconnect path leading to PPE register access
- description: Bus interconnect path leading to QoS generation
- description: Bus interconnect path leading to timeout reference
- description: Bus interconnect path leading to NSS NOC from memory NOC
- description: Bus interconnect path leading to memory NOC from NSS NOC
- description: Bus interconnect path leading to enhanced memory NOC from NSS NOC
interconnect-names:
items:
- const: ppe
- const: ppe_cfg
- const: qos_gen
- const: timeout_ref
- const: nssnoc_memnoc
- const: memnoc_nssnoc
- const: memnoc_nssnoc_1
ethernet-dma:
type: object
additionalProperties: false
description:
EDMA (Ethernet DMA) is used to transmit packets between PPE and ARM
host CPU. There are 32 TX descriptor rings, 32 TX completion rings,
24 RX descriptor rings and 8 RX fill rings supported.
properties:
clocks:
items:
- description: EDMA system clock
- description: EDMA APB (Advanced Peripheral Bus) clock
clock-names:
items:
- const: sys
- const: apb
resets:
maxItems: 1
description: EDMA reset
interrupts:
minItems: 65
maxItems: 65
interrupt-names:
minItems: 65
maxItems: 65
items:
oneOf:
- pattern: '^txcmpl_([1-2]?[0-9]|3[01])$'
- pattern: '^rxfill_[0-7]$'
- pattern: '^rxdesc_(1?[0-9]|2[0-3])$'
- const: misc
description:
Interrupts "txcmpl_[0-31]" are the Ethernet DMA TX completion ring interrupts.
Interrupts "rxfill_[0-7]" are the Ethernet DMA RX fill ring interrupts.
Interrupts "rxdesc_[0-23]" are the Ethernet DMA RX Descriptor ring interrupts.
Interrupt "misc" is the Ethernet DMA miscellaneous error interrupt.
required:
- clocks
- clock-names
- resets
- interrupts
- interrupt-names
ethernet-ports:
patternProperties:
"^ethernet-port@[1-6]+$":
type: object
unevaluatedProperties: false
$ref: ethernet-switch-port.yaml#
properties:
reg:
minimum: 1
maximum: 6
description: PPE Ethernet port ID
clocks:
items:
- description: Port MAC clock
- description: Port RX clock
- description: Port TX clock
clock-names:
items:
- const: mac
- const: rx
- const: tx
resets:
items:
- description: Port MAC reset
- description: Port RX reset
- description: Port TX reset
reset-names:
items:
- const: mac
- const: rx
- const: tx
required:
- reg
- clocks
- clock-names
- resets
- reset-names
required:
- compatible
- reg
- clocks
- clock-names
- resets
- interconnects
- interconnect-names
- ethernet-dma
allOf:
- $ref: ethernet-switch.yaml
unevaluatedProperties: false
examples:
- |
#include <dt-bindings/clock/qcom,ipq9574-gcc.h>
#include <dt-bindings/clock/qcom,ipq9574-nsscc.h>
#include <dt-bindings/interconnect/qcom,ipq9574.h>
#include <dt-bindings/interrupt-controller/arm-gic.h>
#include <dt-bindings/reset/qcom,ipq9574-nsscc.h>
ethernet-switch@3a000000 {
compatible = "qcom,ipq9574-ppe";
reg = <0x3a000000 0xbef800>;
clocks = <&nsscc NSS_CC_PPE_SWITCH_CLK>,
<&nsscc NSS_CC_PPE_SWITCH_CFG_CLK>,
<&nsscc NSS_CC_PPE_SWITCH_IPE_CLK>,
<&nsscc NSS_CC_PPE_SWITCH_BTQ_CLK>;
clock-names = "ppe",
"apb",
"ipe",
"btq";
resets = <&nsscc PPE_FULL_RESET>;
interrupts = <GIC_SPI 498 IRQ_TYPE_LEVEL_HIGH>;
interconnects = <&nsscc MASTER_NSSNOC_PPE &nsscc SLAVE_NSSNOC_PPE>,
<&nsscc MASTER_NSSNOC_PPE_CFG &nsscc SLAVE_NSSNOC_PPE_CFG>,
<&gcc MASTER_NSSNOC_QOSGEN_REF &gcc SLAVE_NSSNOC_QOSGEN_REF>,
<&gcc MASTER_NSSNOC_TIMEOUT_REF &gcc SLAVE_NSSNOC_TIMEOUT_REF>,
<&gcc MASTER_MEM_NOC_NSSNOC &gcc SLAVE_MEM_NOC_NSSNOC>,
<&gcc MASTER_NSSNOC_MEMNOC &gcc SLAVE_NSSNOC_MEMNOC>,
<&gcc MASTER_NSSNOC_MEM_NOC_1 &gcc SLAVE_NSSNOC_MEM_NOC_1>;
interconnect-names = "ppe",
"ppe_cfg",
"qos_gen",
"timeout_ref",
"nssnoc_memnoc",
"memnoc_nssnoc",
"memnoc_nssnoc_1";
ethernet-dma {
clocks = <&nsscc NSS_CC_PPE_EDMA_CLK>,
<&nsscc NSS_CC_PPE_EDMA_CFG_CLK>;
clock-names = "sys",
"apb";
resets = <&nsscc EDMA_HW_RESET>;
interrupts = <GIC_SPI 363 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 364 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 365 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 366 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 367 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 368 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 369 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 370 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 371 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 372 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 373 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 374 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 375 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 376 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 377 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 378 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 379 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 380 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 381 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 382 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 383 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 384 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 509 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 508 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 507 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 506 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 505 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 504 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 503 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 502 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 501 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 500 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 355 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 356 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 357 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 358 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 359 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 360 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 361 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 362 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 331 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 332 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 333 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 334 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 335 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 336 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 337 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 338 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 339 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 340 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 341 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 342 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 343 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 344 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 345 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 346 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 347 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 348 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 349 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 350 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 351 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 352 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 353 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 354 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 499 IRQ_TYPE_LEVEL_HIGH>;
interrupt-names = "txcmpl_0",
"txcmpl_1",
"txcmpl_2",
"txcmpl_3",
"txcmpl_4",
"txcmpl_5",
"txcmpl_6",
"txcmpl_7",
"txcmpl_8",
"txcmpl_9",
"txcmpl_10",
"txcmpl_11",
"txcmpl_12",
"txcmpl_13",
"txcmpl_14",
"txcmpl_15",
"txcmpl_16",
"txcmpl_17",
"txcmpl_18",
"txcmpl_19",
"txcmpl_20",
"txcmpl_21",
"txcmpl_22",
"txcmpl_23",
"txcmpl_24",
"txcmpl_25",
"txcmpl_26",
"txcmpl_27",
"txcmpl_28",
"txcmpl_29",
"txcmpl_30",
"txcmpl_31",
"rxfill_0",
"rxfill_1",
"rxfill_2",
"rxfill_3",
"rxfill_4",
"rxfill_5",
"rxfill_6",
"rxfill_7",
"rxdesc_0",
"rxdesc_1",
"rxdesc_2",
"rxdesc_3",
"rxdesc_4",
"rxdesc_5",
"rxdesc_6",
"rxdesc_7",
"rxdesc_8",
"rxdesc_9",
"rxdesc_10",
"rxdesc_11",
"rxdesc_12",
"rxdesc_13",
"rxdesc_14",
"rxdesc_15",
"rxdesc_16",
"rxdesc_17",
"rxdesc_18",
"rxdesc_19",
"rxdesc_20",
"rxdesc_21",
"rxdesc_22",
"rxdesc_23",
"misc";
};
ethernet-ports {
#address-cells = <1>;
#size-cells = <0>;
ethernet-port@1 {
reg = <1>;
phy-mode = "qsgmii";
managed = "in-band-status";
phy-handle = <&phy0>;
pcs-handle = <&pcs0_ch0>;
clocks = <&nsscc NSS_CC_PORT1_MAC_CLK>,
<&nsscc NSS_CC_PORT1_RX_CLK>,
<&nsscc NSS_CC_PORT1_TX_CLK>;
clock-names = "mac",
"rx",
"tx";
resets = <&nsscc PORT1_MAC_ARES>,
<&nsscc PORT1_RX_ARES>,
<&nsscc PORT1_TX_ARES>;
reset-names = "mac",
"rx",
"tx";
};
ethernet-port@2 {
reg = <2>;
phy-mode = "qsgmii";
managed = "in-band-status";
phy-handle = <&phy1>;
pcs-handle = <&pcs0_ch1>;
clocks = <&nsscc NSS_CC_PORT2_MAC_CLK>,
<&nsscc NSS_CC_PORT2_RX_CLK>,
<&nsscc NSS_CC_PORT2_TX_CLK>;
clock-names = "mac",
"rx",
"tx";
resets = <&nsscc PORT2_MAC_ARES>,
<&nsscc PORT2_RX_ARES>,
<&nsscc PORT2_TX_ARES>;
reset-names = "mac",
"rx",
"tx";
};
ethernet-port@3 {
reg = <3>;
phy-mode = "qsgmii";
managed = "in-band-status";
phy-handle = <&phy2>;
pcs-handle = <&pcs0_ch2>;
clocks = <&nsscc NSS_CC_PORT3_MAC_CLK>,
<&nsscc NSS_CC_PORT3_RX_CLK>,
<&nsscc NSS_CC_PORT3_TX_CLK>;
clock-names = "mac",
"rx",
"tx";
resets = <&nsscc PORT3_MAC_ARES>,
<&nsscc PORT3_RX_ARES>,
<&nsscc PORT3_TX_ARES>;
reset-names = "mac",
"rx",
"tx";
};
ethernet-port@4 {
reg = <4>;
phy-mode = "qsgmii";
managed = "in-band-status";
phy-handle = <&phy3>;
pcs-handle = <&pcs0_ch3>;
clocks = <&nsscc NSS_CC_PORT4_MAC_CLK>,
<&nsscc NSS_CC_PORT4_RX_CLK>,
<&nsscc NSS_CC_PORT4_TX_CLK>;
clock-names = "mac",
"rx",
"tx";
resets = <&nsscc PORT4_MAC_ARES>,
<&nsscc PORT4_RX_ARES>,
<&nsscc PORT4_TX_ARES>;
reset-names = "mac",
"rx",
"tx";
};
ethernet-port@5 {
reg = <5>;
phy-mode = "usxgmii";
managed = "in-band-status";
phy-handle = <&phy4>;
pcs-handle = <&pcs1_ch0>;
clocks = <&nsscc NSS_CC_PORT5_MAC_CLK>,
<&nsscc NSS_CC_PORT5_RX_CLK>,
<&nsscc NSS_CC_PORT5_TX_CLK>;
clock-names = "mac",
"rx",
"tx";
resets = <&nsscc PORT5_MAC_ARES>,
<&nsscc PORT5_RX_ARES>,
<&nsscc PORT5_TX_ARES>;
reset-names = "mac",
"rx",
"tx";
};
ethernet-port@6 {
reg = <6>;
phy-mode = "usxgmii";
managed = "in-band-status";
phy-handle = <&phy5>;
pcs-handle = <&pcs2_ch0>;
clocks = <&nsscc NSS_CC_PORT6_MAC_CLK>,
<&nsscc NSS_CC_PORT6_RX_CLK>,
<&nsscc NSS_CC_PORT6_TX_CLK>;
clock-names = "mac",
"rx",
"tx";
resets = <&nsscc PORT6_MAC_ARES>,
<&nsscc PORT6_RX_ARES>,
<&nsscc PORT6_TX_ARES>;
reset-names = "mac",
"rx",
"tx";
};
};
};

View File

@ -50,6 +50,7 @@ Contents:
neterion/s2io
netronome/nfp
pensando/ionic
qualcomm/ppe/ppe
smsc/smc9
stmicro/stmmac
ti/cpsw

View File

@ -0,0 +1,194 @@
.. SPDX-License-Identifier: GPL-2.0
===============================================
PPE Ethernet Driver for Qualcomm IPQ SoC Family
===============================================
Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
Author: Lei Wei <quic_leiwei@quicinc.com>
Contents
========
- `PPE Overview`_
- `PPE Driver Overview`_
- `PPE Driver Supported SoCs`_
- `Enabling the Driver`_
- `Debugging`_
PPE Overview
============
IPQ (Qualcomm Internet Processor) SoC (System-on-Chip) series is Qualcomm's series of
networking SoC for Wi-Fi access points. The PPE (Packet Process Engine) is the Ethernet
packet process engine in the IPQ SoC.
Below is a simplified hardware diagram of IPQ9574 SoC which includes the PPE engine and
other blocks which are in the SoC but outside the PPE engine. These blocks work together
to enable the Ethernet for the IPQ SoC::
+------+ +------+ +------+ +------+ +------+ +------+ start +-------+
|netdev| |netdev| |netdev| |netdev| |netdev| |netdev|<------|PHYLINK|
+------+ +------+ +------+ +------+ +------+ +------+ stop +-+-+-+-+
| | | ^
+-------+ +-------------------------+--------+----------------------+ | | |
| GCC | | | EDMA | | | | |
+---+---+ | PPE +---+----+ | | | |
| clk | | | | | |
+-------->| +-----------------------+------+-----+---------------+ | | | |
| | Switch Core |Port0 | |Port7(EIP FIFO)| | | | |
| | +---+--+ +------+--------+ | | | |
| | | | | | | | |
+-------+ | | +------+---------------+----+ | | | | |
|CMN PLL| | | +---+ +---+ +----+ | +--------+ | | | | | |
+---+---+ | | |BM | |QM | |SCH | | | L2/L3 | ....... | | | | | |
| | | | +---+ +---+ +----+ | +--------+ | | | | | |
| | | | +------+--------------------+ | | | | |
| | | | | | | | | |
| v | | +-----+-+-----+-+-----+-+-+---+--+-----+-+-----+ | | | | |
| +------+ | | |Port1| |Port2| |Port3| |Port4| |Port5| |Port6| | | | | |
| |NSSCC | | | +-----+ +-----+ +-----+ +-----+ +-----+ +-----+ | | mac| | |
| +-+-+--+ | | |MAC0 | |MAC1 | |MAC2 | |MAC3 | |MAC4 | |MAC5 | | |<---+ | |
| ^ | |clk | | +-----+-+-----+-+-----+-+-----+--+-----+-+-----+ | | ops | |
| | | +------>| +----|------|-------|-------|---------|--------|-----+ | | |
| | | +---------------------------------------------------------+ | |
| | | | | | | | | | |
| | | MII clk | QSGMII USXGMII USXGMII | |
| | +--------------->| | | | | | | |
| | +-------------------------+ +---------+ +---------+ | |
| |125/312.5MHz clk| (PCS0) | | (PCS1) | | (PCS2) | pcs ops | |
| +----------------+ UNIPHY0 | | UNIPHY1 | | UNIPHY2 |<--------+ |
+----------------->| | | | | | |
| 31.25MHz ref clk +-------------------------+ +---------+ +---------+ |
| | | | | | | |
| +-----------------------------------------------------+ |
|25/50MHz ref clk| +-------------------------+ +------+ +------+ | link |
+--------------->| | QUAD PHY | | PHY4 | | PHY5 | |---------+
| +-------------------------+ +------+ +------+ | change
| |
| MDIO bus |
+-----------------------------------------------------+
The CMN (Common) PLL, NSSCC (Networking Sub System Clock Controller) and GCC (Global
Clock Controller) blocks are in the SoC and act as clock providers.
The UNIPHY block is in the SoC and provides the PCS (Physical Coding Sublayer) and
XPCS (10-Gigabit Physical Coding Sublayer) functions to support different interface
modes between the PPE MAC and the external PHY.
This documentation focuses on the descriptions of PPE engine and the PPE driver.
The Ethernet functionality in the PPE (Packet Process Engine) is comprised of three
components: the switch core, port wrapper and Ethernet DMA.
The Switch core in the IPQ9574 PPE has maximum of 6 front panel ports and two FIFO
interfaces. One of the two FIFO interfaces is used for Ethernet port to host CPU
communication using Ethernet DMA. The other one is used to communicate to the EIP
engine which is used for IPsec offload. On the IPQ9574, the PPE includes 6 GMAC/XGMACs
that can be connected with external Ethernet PHY. Switch core also includes BM (Buffer
Management), QM (Queue Management) and SCH (Scheduler) modules for supporting the
packet processing.
The port wrapper provides connections from the 6 GMAC/XGMACS to UNIPHY (PCS) supporting
various modes such as SGMII/QSGMII/PSGMII/USXGMII/10G-BASER. There are 3 UNIPHY (PCS)
instances supported on the IPQ9574.
Ethernet DMA is used to transmit and receive packets between the Ethernet subsystem
and ARM host CPU.
The following lists the main blocks in the PPE engine which will be driven by this
PPE driver:
- BM
BM is the hardware buffer manager for the PPE switch ports.
- QM
Queue Manager for managing the egress hardware queues of the PPE switch ports.
- SCH
The scheduler which manages the hardware traffic scheduling for the PPE switch ports.
- L2
The L2 block performs the packet bridging in the switch core. The bridge domain is
represented by the VSI (Virtual Switch Instance) domain in PPE. FDB learning can be
enabled based on the VSI domain and bridge forwarding occurs within the VSI domain.
- MAC
The PPE in the IPQ9574 supports up to six MACs (MAC0 to MAC5) which are corresponding
to six switch ports (port1 to port6). The MAC block is connected with external PHY
through the UNIPHY PCS block. Each MAC block includes the GMAC and XGMAC blocks and
the switch port can select to use GMAC or XMAC through a MUX selection according to
the external PHY's capability.
- EDMA (Ethernet DMA)
The Ethernet DMA is used to transmit and receive Ethernet packets between the PPE
ports and the ARM cores.
The received packet on a PPE MAC port can be forwarded to another PPE MAC port. It can
be also forwarded to internal switch port0 so that the packet can be delivered to the
ARM cores using the Ethernet DMA (EDMA) engine. The Ethernet DMA driver will deliver the
packet to the corresponding 'netdevice' interface.
The software instantiations of the PPE MAC (netdevice), PCS and external PHYs interact
with the Linux PHYLINK framework to manage the connectivity between the PPE ports and
the connected PHYs, and the port link states. This is also illustrated in above diagram.
PPE Driver Overview
===================
PPE driver is Ethernet driver for the Qualcomm IPQ SoC. It is a single platform driver
which includes the PPE part and Ethernet DMA part. The PPE part initializes and drives the
various blocks in PPE switch core such as BM/QM/L2 blocks and the PPE MACs. The EDMA part
drives the Ethernet DMA for packet transfer between PPE ports and ARM cores, and enables
the netdevice driver for the PPE ports.
The PPE driver files in drivers/net/ethernet/qualcomm/ppe/ are listed as below:
- Makefile
- ppe.c
- ppe.h
- ppe_config.c
- ppe_config.h
- ppe_debugfs.c
- ppe_debugfs.h
- ppe_regs.h
The ppe.c file contains the main PPE platform driver and undertakes the initialization of
PPE switch core blocks such as QM, BM and L2. The configuration APIs for these hardware
blocks are provided in the ppe_config.c file.
The ppe.h defines the PPE device data structure which will be used by PPE driver functions.
The ppe_debugfs.c enables the PPE statistics counters such as PPE port Rx and Tx counters,
CPU code counters and queue counters.
PPE Driver Supported SoCs
=========================
The PPE driver supports the following IPQ SoC:
- IPQ9574
Enabling the Driver
===================
The driver is located in the menu structure at::
-> Device Drivers
-> Network device support (NETDEVICES [=y])
-> Ethernet driver support
-> Qualcomm devices
-> Qualcomm Technologies, Inc. PPE Ethernet support
If the driver is built as a module, the module will be called qcom-ppe.
The PPE driver functionally depends on the CMN PLL and NSSCC clock controller drivers.
Please make sure the dependent modules are installed before installing the PPE driver
module.
Debugging
=========
The PPE hardware counters can be accessed using debugfs interface from the
``/sys/kernel/debug/ppe/`` directory.

View File

@ -20836,6 +20836,14 @@ S: Maintained
F: Documentation/devicetree/bindings/power/supply/qcom,pmi8998-charger.yaml
F: drivers/power/supply/qcom_smbx.c
QUALCOMM PPE DRIVER
M: Luo Jie <quic_luoj@quicinc.com>
L: netdev@vger.kernel.org
S: Supported
F: Documentation/devicetree/bindings/net/qcom,ipq9574-ppe.yaml
F: Documentation/networking/device_drivers/ethernet/qualcomm/ppe/ppe.rst
F: drivers/net/ethernet/qualcomm/ppe/
QUALCOMM QSEECOM DRIVER
M: Maximilian Luz <luzmaximilian@gmail.com>
L: linux-arm-msm@vger.kernel.org

View File

@ -60,6 +60,21 @@ config QCOM_EMAC
low power, Receive-Side Scaling (RSS), and IEEE 1588-2008
Precision Clock Synchronization Protocol.
config QCOM_PPE
tristate "Qualcomm Technologies, Inc. PPE Ethernet support"
depends on HAS_IOMEM && OF
depends on COMMON_CLK
select REGMAP_MMIO
help
This driver supports the Qualcomm Technologies, Inc. packet
process engine (PPE) available with IPQ SoC. The PPE includes
the Ethernet MACs, Ethernet DMA (EDMA) and switch core that
supports L3 flow offload, L2 switch function, RSS and tunnel
offload.
To compile this driver as a module, choose M here. The module
will be called qcom-ppe.
source "drivers/net/ethernet/qualcomm/rmnet/Kconfig"
endif # NET_VENDOR_QUALCOMM

View File

@ -11,4 +11,5 @@ qcauart-objs := qca_uart.o
obj-y += emac/
obj-$(CONFIG_QCOM_PPE) += ppe/
obj-$(CONFIG_RMNET) += rmnet/

View File

@ -0,0 +1,7 @@
# SPDX-License-Identifier: GPL-2.0-only
#
# Makefile for the device driver of PPE (Packet Process Engine) in IPQ SoC
#
obj-$(CONFIG_QCOM_PPE) += qcom-ppe.o
qcom-ppe-objs := ppe.o ppe_config.o ppe_debugfs.o

View File

@ -0,0 +1,239 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
*/
/* PPE platform device probe, DTSI parser and PPE clock initializations. */
#include <linux/clk.h>
#include <linux/interconnect.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/regmap.h>
#include <linux/reset.h>
#include "ppe.h"
#include "ppe_config.h"
#include "ppe_debugfs.h"
#define PPE_PORT_MAX 8
#define PPE_CLK_RATE 353000000
/* ICC clocks for enabling PPE device. The avg_bw and peak_bw with value 0
* will be updated by the clock rate of PPE.
*/
static const struct icc_bulk_data ppe_icc_data[] = {
{
.name = "ppe",
.avg_bw = 0,
.peak_bw = 0,
},
{
.name = "ppe_cfg",
.avg_bw = 0,
.peak_bw = 0,
},
{
.name = "qos_gen",
.avg_bw = 6000,
.peak_bw = 6000,
},
{
.name = "timeout_ref",
.avg_bw = 6000,
.peak_bw = 6000,
},
{
.name = "nssnoc_memnoc",
.avg_bw = 533333,
.peak_bw = 533333,
},
{
.name = "memnoc_nssnoc",
.avg_bw = 533333,
.peak_bw = 533333,
},
{
.name = "memnoc_nssnoc_1",
.avg_bw = 533333,
.peak_bw = 533333,
},
};
static const struct regmap_range ppe_readable_ranges[] = {
regmap_reg_range(0x0, 0x1ff), /* Global */
regmap_reg_range(0x400, 0x5ff), /* LPI CSR */
regmap_reg_range(0x1000, 0x11ff), /* GMAC0 */
regmap_reg_range(0x1200, 0x13ff), /* GMAC1 */
regmap_reg_range(0x1400, 0x15ff), /* GMAC2 */
regmap_reg_range(0x1600, 0x17ff), /* GMAC3 */
regmap_reg_range(0x1800, 0x19ff), /* GMAC4 */
regmap_reg_range(0x1a00, 0x1bff), /* GMAC5 */
regmap_reg_range(0xb000, 0xefff), /* PRX CSR */
regmap_reg_range(0xf000, 0x1efff), /* IPE */
regmap_reg_range(0x20000, 0x5ffff), /* PTX CSR */
regmap_reg_range(0x60000, 0x9ffff), /* IPE L2 CSR */
regmap_reg_range(0xb0000, 0xeffff), /* IPO CSR */
regmap_reg_range(0x100000, 0x17ffff), /* IPE PC */
regmap_reg_range(0x180000, 0x1bffff), /* PRE IPO CSR */
regmap_reg_range(0x1d0000, 0x1dffff), /* Tunnel parser */
regmap_reg_range(0x1e0000, 0x1effff), /* Ingress parse */
regmap_reg_range(0x200000, 0x2fffff), /* IPE L3 */
regmap_reg_range(0x300000, 0x3fffff), /* IPE tunnel */
regmap_reg_range(0x400000, 0x4fffff), /* Scheduler */
regmap_reg_range(0x500000, 0x503fff), /* XGMAC0 */
regmap_reg_range(0x504000, 0x507fff), /* XGMAC1 */
regmap_reg_range(0x508000, 0x50bfff), /* XGMAC2 */
regmap_reg_range(0x50c000, 0x50ffff), /* XGMAC3 */
regmap_reg_range(0x510000, 0x513fff), /* XGMAC4 */
regmap_reg_range(0x514000, 0x517fff), /* XGMAC5 */
regmap_reg_range(0x600000, 0x6fffff), /* BM */
regmap_reg_range(0x800000, 0x9fffff), /* QM */
regmap_reg_range(0xb00000, 0xbef800), /* EDMA */
};
static const struct regmap_access_table ppe_reg_table = {
.yes_ranges = ppe_readable_ranges,
.n_yes_ranges = ARRAY_SIZE(ppe_readable_ranges),
};
static const struct regmap_config regmap_config_ipq9574 = {
.reg_bits = 32,
.reg_stride = 4,
.val_bits = 32,
.rd_table = &ppe_reg_table,
.wr_table = &ppe_reg_table,
.max_register = 0xbef800,
.fast_io = true,
};
static int ppe_clock_init_and_reset(struct ppe_device *ppe_dev)
{
unsigned long ppe_rate = ppe_dev->clk_rate;
struct device *dev = ppe_dev->dev;
struct reset_control *rstc;
struct clk_bulk_data *clks;
struct clk *clk;
int ret, i;
for (i = 0; i < ppe_dev->num_icc_paths; i++) {
ppe_dev->icc_paths[i].name = ppe_icc_data[i].name;
ppe_dev->icc_paths[i].avg_bw = ppe_icc_data[i].avg_bw ? :
Bps_to_icc(ppe_rate);
/* PPE does not have an explicit peak bandwidth requirement,
* so set the peak bandwidth to be equal to the average
* bandwidth.
*/
ppe_dev->icc_paths[i].peak_bw = ppe_icc_data[i].peak_bw ? :
Bps_to_icc(ppe_rate);
}
ret = devm_of_icc_bulk_get(dev, ppe_dev->num_icc_paths,
ppe_dev->icc_paths);
if (ret)
return ret;
ret = icc_bulk_set_bw(ppe_dev->num_icc_paths, ppe_dev->icc_paths);
if (ret)
return ret;
/* The PPE clocks have a common parent clock. Setting the clock
* rate of "ppe" ensures the clock rate of all PPE clocks is
* configured to the same rate.
*/
clk = devm_clk_get(dev, "ppe");
if (IS_ERR(clk))
return PTR_ERR(clk);
ret = clk_set_rate(clk, ppe_rate);
if (ret)
return ret;
ret = devm_clk_bulk_get_all_enabled(dev, &clks);
if (ret < 0)
return ret;
/* Reset the PPE. */
rstc = devm_reset_control_get_exclusive(dev, NULL);
if (IS_ERR(rstc))
return PTR_ERR(rstc);
ret = reset_control_assert(rstc);
if (ret)
return ret;
/* The delay 10 ms of assert is necessary for resetting PPE. */
usleep_range(10000, 11000);
return reset_control_deassert(rstc);
}
static int qcom_ppe_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct ppe_device *ppe_dev;
void __iomem *base;
int ret, num_icc;
num_icc = ARRAY_SIZE(ppe_icc_data);
ppe_dev = devm_kzalloc(dev, struct_size(ppe_dev, icc_paths, num_icc),
GFP_KERNEL);
if (!ppe_dev)
return -ENOMEM;
base = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(base))
return dev_err_probe(dev, PTR_ERR(base), "PPE ioremap failed\n");
ppe_dev->regmap = devm_regmap_init_mmio(dev, base, &regmap_config_ipq9574);
if (IS_ERR(ppe_dev->regmap))
return dev_err_probe(dev, PTR_ERR(ppe_dev->regmap),
"PPE initialize regmap failed\n");
ppe_dev->dev = dev;
ppe_dev->clk_rate = PPE_CLK_RATE;
ppe_dev->num_ports = PPE_PORT_MAX;
ppe_dev->num_icc_paths = num_icc;
ret = ppe_clock_init_and_reset(ppe_dev);
if (ret)
return dev_err_probe(dev, ret, "PPE clock config failed\n");
ret = ppe_hw_config(ppe_dev);
if (ret)
return dev_err_probe(dev, ret, "PPE HW config failed\n");
ppe_debugfs_setup(ppe_dev);
platform_set_drvdata(pdev, ppe_dev);
return 0;
}
static void qcom_ppe_remove(struct platform_device *pdev)
{
struct ppe_device *ppe_dev;
ppe_dev = platform_get_drvdata(pdev);
ppe_debugfs_teardown(ppe_dev);
}
static const struct of_device_id qcom_ppe_of_match[] = {
{ .compatible = "qcom,ipq9574-ppe" },
{}
};
MODULE_DEVICE_TABLE(of, qcom_ppe_of_match);
static struct platform_driver qcom_ppe_driver = {
.driver = {
.name = "qcom_ppe",
.of_match_table = qcom_ppe_of_match,
},
.probe = qcom_ppe_probe,
.remove = qcom_ppe_remove,
};
module_platform_driver(qcom_ppe_driver);
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Qualcomm Technologies, Inc. IPQ PPE driver");

View File

@ -0,0 +1,39 @@
/* SPDX-License-Identifier: GPL-2.0-only
*
* Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
*/
#ifndef __PPE_H__
#define __PPE_H__
#include <linux/compiler.h>
#include <linux/interconnect.h>
struct device;
struct regmap;
struct dentry;
/**
* struct ppe_device - PPE device private data.
* @dev: PPE device structure.
* @regmap: PPE register map.
* @clk_rate: PPE clock rate.
* @num_ports: Number of PPE ports.
* @debugfs_root: Debugfs root entry.
* @num_icc_paths: Number of interconnect paths.
* @icc_paths: Interconnect path array.
*
* PPE device is the instance of PPE hardware, which is used to
* configure PPE packet process modules such as BM (buffer management),
* QM (queue management), and scheduler.
*/
struct ppe_device {
struct device *dev;
struct regmap *regmap;
unsigned long clk_rate;
unsigned int num_ports;
struct dentry *debugfs_root;
unsigned int num_icc_paths;
struct icc_bulk_data icc_paths[] __counted_by(num_icc_paths);
};
#endif

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,317 @@
/* SPDX-License-Identifier: GPL-2.0-only
*
* Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
*/
#ifndef __PPE_CONFIG_H__
#define __PPE_CONFIG_H__
#include <linux/types.h>
#include "ppe.h"
/* There are different table index ranges for configuring queue base ID of
* the destination port, CPU code and service code.
*/
#define PPE_QUEUE_BASE_DEST_PORT 0
#define PPE_QUEUE_BASE_CPU_CODE 1024
#define PPE_QUEUE_BASE_SERVICE_CODE 2048
#define PPE_QUEUE_INTER_PRI_NUM 16
#define PPE_QUEUE_HASH_NUM 256
/* The service code is used by EDMA port to transmit packet to PPE. */
#define PPE_EDMA_SC_BYPASS_ID 1
/* The PPE RSS hash configured for IPv4 and IPv6 packet separately. */
#define PPE_RSS_HASH_MODE_IPV4 BIT(0)
#define PPE_RSS_HASH_MODE_IPV6 BIT(1)
#define PPE_RSS_HASH_IP_LENGTH 4
#define PPE_RSS_HASH_TUPLES 5
/* PPE supports 300 queues, each bit presents as one queue. */
#define PPE_RING_TO_QUEUE_BITMAP_WORD_CNT 10
/**
* enum ppe_scheduler_frame_mode - PPE scheduler frame mode.
* @PPE_SCH_WITH_IPG_PREAMBLE_FRAME_CRC: The scheduled frame includes IPG,
* preamble, Ethernet packet and CRC.
* @PPE_SCH_WITH_FRAME_CRC: The scheduled frame includes Ethernet frame and CRC
* excluding IPG and preamble.
* @PPE_SCH_WITH_L3_PAYLOAD: The scheduled frame includes layer 3 packet data.
*/
enum ppe_scheduler_frame_mode {
PPE_SCH_WITH_IPG_PREAMBLE_FRAME_CRC = 0,
PPE_SCH_WITH_FRAME_CRC = 1,
PPE_SCH_WITH_L3_PAYLOAD = 2,
};
/**
* struct ppe_scheduler_cfg - PPE scheduler configuration.
* @flow_id: PPE flow ID.
* @pri: Scheduler priority.
* @drr_node_id: Node ID for scheduled traffic.
* @drr_node_wt: Weight for scheduled traffic.
* @unit_is_packet: Packet based or byte based unit for scheduled traffic.
* @frame_mode: Packet mode to be scheduled.
*
* PPE scheduler supports commit rate and exceed rate configurations.
*/
struct ppe_scheduler_cfg {
int flow_id;
int pri;
int drr_node_id;
int drr_node_wt;
bool unit_is_packet;
enum ppe_scheduler_frame_mode frame_mode;
};
/**
* enum ppe_resource_type - PPE resource type.
* @PPE_RES_UCAST: Unicast queue resource.
* @PPE_RES_MCAST: Multicast queue resource.
* @PPE_RES_L0_NODE: Level 0 for queue based node resource.
* @PPE_RES_L1_NODE: Level 1 for flow based node resource.
* @PPE_RES_FLOW_ID: Flow based node resource.
*/
enum ppe_resource_type {
PPE_RES_UCAST,
PPE_RES_MCAST,
PPE_RES_L0_NODE,
PPE_RES_L1_NODE,
PPE_RES_FLOW_ID,
};
/**
* struct ppe_queue_ucast_dest - PPE unicast queue destination.
* @src_profile: Source profile.
* @service_code_en: Enable service code to map the queue base ID.
* @service_code: Service code.
* @cpu_code_en: Enable CPU code to map the queue base ID.
* @cpu_code: CPU code.
* @dest_port: destination port.
*
* PPE egress queue ID is decided by the service code if enabled, otherwise
* by the CPU code if enabled, or by destination port if both service code
* and CPU code are disabled.
*/
struct ppe_queue_ucast_dest {
int src_profile;
bool service_code_en;
int service_code;
bool cpu_code_en;
int cpu_code;
int dest_port;
};
/* Hardware bitmaps for bypassing features of the ingress packet. */
enum ppe_sc_ingress_type {
PPE_SC_BYPASS_INGRESS_VLAN_TAG_FMT_CHECK = 0,
PPE_SC_BYPASS_INGRESS_VLAN_MEMBER_CHECK = 1,
PPE_SC_BYPASS_INGRESS_VLAN_TRANSLATE = 2,
PPE_SC_BYPASS_INGRESS_MY_MAC_CHECK = 3,
PPE_SC_BYPASS_INGRESS_DIP_LOOKUP = 4,
PPE_SC_BYPASS_INGRESS_FLOW_LOOKUP = 5,
PPE_SC_BYPASS_INGRESS_FLOW_ACTION = 6,
PPE_SC_BYPASS_INGRESS_ACL = 7,
PPE_SC_BYPASS_INGRESS_FAKE_MAC_HEADER = 8,
PPE_SC_BYPASS_INGRESS_SERVICE_CODE = 9,
PPE_SC_BYPASS_INGRESS_WRONG_PKT_FMT_L2 = 10,
PPE_SC_BYPASS_INGRESS_WRONG_PKT_FMT_L3_IPV4 = 11,
PPE_SC_BYPASS_INGRESS_WRONG_PKT_FMT_L3_IPV6 = 12,
PPE_SC_BYPASS_INGRESS_WRONG_PKT_FMT_L4 = 13,
PPE_SC_BYPASS_INGRESS_FLOW_SERVICE_CODE = 14,
PPE_SC_BYPASS_INGRESS_ACL_SERVICE_CODE = 15,
PPE_SC_BYPASS_INGRESS_FAKE_L2_PROTO = 16,
PPE_SC_BYPASS_INGRESS_PPPOE_TERMINATION = 17,
PPE_SC_BYPASS_INGRESS_DEFAULT_VLAN = 18,
PPE_SC_BYPASS_INGRESS_DEFAULT_PCP = 19,
PPE_SC_BYPASS_INGRESS_VSI_ASSIGN = 20,
/* Values 21-23 are not specified by hardware. */
PPE_SC_BYPASS_INGRESS_VLAN_ASSIGN_FAIL = 24,
PPE_SC_BYPASS_INGRESS_SOURCE_GUARD = 25,
PPE_SC_BYPASS_INGRESS_MRU_MTU_CHECK = 26,
PPE_SC_BYPASS_INGRESS_FLOW_SRC_CHECK = 27,
PPE_SC_BYPASS_INGRESS_FLOW_QOS = 28,
/* This must be last as it determines the size of the BITMAP. */
PPE_SC_BYPASS_INGRESS_SIZE,
};
/* Hardware bitmaps for bypassing features of the egress packet. */
enum ppe_sc_egress_type {
PPE_SC_BYPASS_EGRESS_VLAN_MEMBER_CHECK = 0,
PPE_SC_BYPASS_EGRESS_VLAN_TRANSLATE = 1,
PPE_SC_BYPASS_EGRESS_VLAN_TAG_FMT_CTRL = 2,
PPE_SC_BYPASS_EGRESS_FDB_LEARN = 3,
PPE_SC_BYPASS_EGRESS_FDB_REFRESH = 4,
PPE_SC_BYPASS_EGRESS_L2_SOURCE_SECURITY = 5,
PPE_SC_BYPASS_EGRESS_MANAGEMENT_FWD = 6,
PPE_SC_BYPASS_EGRESS_BRIDGING_FWD = 7,
PPE_SC_BYPASS_EGRESS_IN_STP_FLTR = 8,
PPE_SC_BYPASS_EGRESS_EG_STP_FLTR = 9,
PPE_SC_BYPASS_EGRESS_SOURCE_FLTR = 10,
PPE_SC_BYPASS_EGRESS_POLICER = 11,
PPE_SC_BYPASS_EGRESS_L2_PKT_EDIT = 12,
PPE_SC_BYPASS_EGRESS_L3_PKT_EDIT = 13,
PPE_SC_BYPASS_EGRESS_ACL_POST_ROUTING_CHECK = 14,
PPE_SC_BYPASS_EGRESS_PORT_ISOLATION = 15,
PPE_SC_BYPASS_EGRESS_PRE_ACL_QOS = 16,
PPE_SC_BYPASS_EGRESS_POST_ACL_QOS = 17,
PPE_SC_BYPASS_EGRESS_DSCP_QOS = 18,
PPE_SC_BYPASS_EGRESS_PCP_QOS = 19,
PPE_SC_BYPASS_EGRESS_PREHEADER_QOS = 20,
PPE_SC_BYPASS_EGRESS_FAKE_MAC_DROP = 21,
PPE_SC_BYPASS_EGRESS_TUNL_CONTEXT = 22,
PPE_SC_BYPASS_EGRESS_FLOW_POLICER = 23,
/* This must be last as it determines the size of the BITMAP. */
PPE_SC_BYPASS_EGRESS_SIZE,
};
/* Hardware bitmaps for bypassing counter of packet. */
enum ppe_sc_counter_type {
PPE_SC_BYPASS_COUNTER_RX_VLAN = 0,
PPE_SC_BYPASS_COUNTER_RX = 1,
PPE_SC_BYPASS_COUNTER_TX_VLAN = 2,
PPE_SC_BYPASS_COUNTER_TX = 3,
/* This must be last as it determines the size of the BITMAP. */
PPE_SC_BYPASS_COUNTER_SIZE,
};
/* Hardware bitmaps for bypassing features of tunnel packet. */
enum ppe_sc_tunnel_type {
PPE_SC_BYPASS_TUNNEL_SERVICE_CODE = 0,
PPE_SC_BYPASS_TUNNEL_TUNNEL_HANDLE = 1,
PPE_SC_BYPASS_TUNNEL_L3_IF_CHECK = 2,
PPE_SC_BYPASS_TUNNEL_VLAN_CHECK = 3,
PPE_SC_BYPASS_TUNNEL_DMAC_CHECK = 4,
PPE_SC_BYPASS_TUNNEL_UDP_CSUM_0_CHECK = 5,
PPE_SC_BYPASS_TUNNEL_TBL_DE_ACCE_CHECK = 6,
PPE_SC_BYPASS_TUNNEL_PPPOE_MC_TERM_CHECK = 7,
PPE_SC_BYPASS_TUNNEL_TTL_EXCEED_CHECK = 8,
PPE_SC_BYPASS_TUNNEL_MAP_SRC_CHECK = 9,
PPE_SC_BYPASS_TUNNEL_MAP_DST_CHECK = 10,
PPE_SC_BYPASS_TUNNEL_LPM_DST_LOOKUP = 11,
PPE_SC_BYPASS_TUNNEL_LPM_LOOKUP = 12,
PPE_SC_BYPASS_TUNNEL_WRONG_PKT_FMT_L2 = 13,
PPE_SC_BYPASS_TUNNEL_WRONG_PKT_FMT_L3_IPV4 = 14,
PPE_SC_BYPASS_TUNNEL_WRONG_PKT_FMT_L3_IPV6 = 15,
PPE_SC_BYPASS_TUNNEL_WRONG_PKT_FMT_L4 = 16,
PPE_SC_BYPASS_TUNNEL_WRONG_PKT_FMT_TUNNEL = 17,
/* Values 18-19 are not specified by hardware. */
PPE_SC_BYPASS_TUNNEL_PRE_IPO = 20,
/* This must be last as it determines the size of the BITMAP. */
PPE_SC_BYPASS_TUNNEL_SIZE,
};
/**
* struct ppe_sc_bypass - PPE service bypass bitmaps
* @ingress: Bitmap of features that can be bypassed on the ingress packet.
* @egress: Bitmap of features that can be bypassed on the egress packet.
* @counter: Bitmap of features that can be bypassed on the counter type.
* @tunnel: Bitmap of features that can be bypassed on the tunnel packet.
*/
struct ppe_sc_bypass {
DECLARE_BITMAP(ingress, PPE_SC_BYPASS_INGRESS_SIZE);
DECLARE_BITMAP(egress, PPE_SC_BYPASS_EGRESS_SIZE);
DECLARE_BITMAP(counter, PPE_SC_BYPASS_COUNTER_SIZE);
DECLARE_BITMAP(tunnel, PPE_SC_BYPASS_TUNNEL_SIZE);
};
/**
* struct ppe_sc_cfg - PPE service code configuration.
* @dest_port_valid: Generate destination port or not.
* @dest_port: Destination port ID.
* @bitmaps: Bitmap of bypass features.
* @is_src: Destination port acts as source port, packet sent to CPU.
* @next_service_code: New service code generated.
* @eip_field_update_bitmap: Fields updated as actions taken for EIP.
* @eip_hw_service: Selected hardware functions for EIP.
* @eip_offset_sel: Packet offset selection, using packet's layer 4 offset
* or using packet's layer 3 offset for EIP.
*
* Service code is generated during the packet passing through PPE.
*/
struct ppe_sc_cfg {
bool dest_port_valid;
int dest_port;
struct ppe_sc_bypass bitmaps;
bool is_src;
int next_service_code;
int eip_field_update_bitmap;
int eip_hw_service;
int eip_offset_sel;
};
/**
* enum ppe_action_type - PPE action of the received packet.
* @PPE_ACTION_FORWARD: Packet forwarded per L2/L3 process.
* @PPE_ACTION_DROP: Packet dropped by PPE.
* @PPE_ACTION_COPY_TO_CPU: Packet copied to CPU port per multicast queue.
* @PPE_ACTION_REDIRECT_TO_CPU: Packet redirected to CPU port per unicast queue.
*/
enum ppe_action_type {
PPE_ACTION_FORWARD = 0,
PPE_ACTION_DROP = 1,
PPE_ACTION_COPY_TO_CPU = 2,
PPE_ACTION_REDIRECT_TO_CPU = 3,
};
/**
* struct ppe_rss_hash_cfg - PPE RSS hash configuration.
* @hash_mask: Mask of the generated hash value.
* @hash_fragment_mode: Hash generation mode for the first fragment of TCP,
* UDP and UDP-Lite packets, to use either 3 tuple or 5 tuple for RSS hash
* key computation.
* @hash_seed: Seed to generate RSS hash.
* @hash_sip_mix: Source IP selection.
* @hash_dip_mix: Destination IP selection.
* @hash_protocol_mix: Protocol selection.
* @hash_sport_mix: Source L4 port selection.
* @hash_dport_mix: Destination L4 port selection.
* @hash_fin_inner: RSS hash value first selection.
* @hash_fin_outer: RSS hash value second selection.
*
* PPE RSS hash value is generated for the packet based on the RSS hash
* configured.
*/
struct ppe_rss_hash_cfg {
u32 hash_mask;
bool hash_fragment_mode;
u32 hash_seed;
u8 hash_sip_mix[PPE_RSS_HASH_IP_LENGTH];
u8 hash_dip_mix[PPE_RSS_HASH_IP_LENGTH];
u8 hash_protocol_mix;
u8 hash_sport_mix;
u8 hash_dport_mix;
u8 hash_fin_inner[PPE_RSS_HASH_TUPLES];
u8 hash_fin_outer[PPE_RSS_HASH_TUPLES];
};
int ppe_hw_config(struct ppe_device *ppe_dev);
int ppe_queue_scheduler_set(struct ppe_device *ppe_dev,
int node_id, bool flow_level, int port,
struct ppe_scheduler_cfg scheduler_cfg);
int ppe_queue_ucast_base_set(struct ppe_device *ppe_dev,
struct ppe_queue_ucast_dest queue_dst,
int queue_base,
int profile_id);
int ppe_queue_ucast_offset_pri_set(struct ppe_device *ppe_dev,
int profile_id,
int priority,
int queue_offset);
int ppe_queue_ucast_offset_hash_set(struct ppe_device *ppe_dev,
int profile_id,
int rss_hash,
int queue_offset);
int ppe_port_resource_get(struct ppe_device *ppe_dev, int port,
enum ppe_resource_type type,
int *res_start, int *res_end);
int ppe_sc_config_set(struct ppe_device *ppe_dev, int sc,
struct ppe_sc_cfg cfg);
int ppe_counter_enable_set(struct ppe_device *ppe_dev, int port);
int ppe_rss_hash_config_set(struct ppe_device *ppe_dev, int mode,
struct ppe_rss_hash_cfg hash_cfg);
int ppe_ring_queue_map_set(struct ppe_device *ppe_dev,
int ring_id,
u32 *queue_map);
#endif

View File

@ -0,0 +1,847 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
*/
/* PPE debugfs routines for display of PPE counters useful for debug. */
#include <linux/bitfield.h>
#include <linux/debugfs.h>
#include <linux/dev_printk.h>
#include <linux/device.h>
#include <linux/regmap.h>
#include <linux/seq_file.h>
#include "ppe.h"
#include "ppe_config.h"
#include "ppe_debugfs.h"
#include "ppe_regs.h"
#define PPE_PKT_CNT_TBL_SIZE 3
#define PPE_DROP_PKT_CNT_TBL_SIZE 5
#define PPE_W0_PKT_CNT GENMASK(31, 0)
#define PPE_W2_DROP_PKT_CNT_LOW GENMASK(31, 8)
#define PPE_W3_DROP_PKT_CNT_HIGH GENMASK(7, 0)
#define PPE_GET_PKT_CNT(tbl_cnt) \
FIELD_GET(PPE_W0_PKT_CNT, *(tbl_cnt))
#define PPE_GET_DROP_PKT_CNT_LOW(tbl_cnt) \
FIELD_GET(PPE_W2_DROP_PKT_CNT_LOW, *((tbl_cnt) + 0x2))
#define PPE_GET_DROP_PKT_CNT_HIGH(tbl_cnt) \
FIELD_GET(PPE_W3_DROP_PKT_CNT_HIGH, *((tbl_cnt) + 0x3))
/**
* enum ppe_cnt_size_type - PPE counter size type
* @PPE_PKT_CNT_SIZE_1WORD: Counter size with single register
* @PPE_PKT_CNT_SIZE_3WORD: Counter size with table of 3 words
* @PPE_PKT_CNT_SIZE_5WORD: Counter size with table of 5 words
*
* PPE takes the different register size to record the packet counters.
* It uses single register, or register table with 3 words or 5 words.
* The counter with table size 5 words also records the drop counter.
* There are also some other counter types occupying sizes less than 32
* bits, which is not covered by this enumeration type.
*/
enum ppe_cnt_size_type {
PPE_PKT_CNT_SIZE_1WORD,
PPE_PKT_CNT_SIZE_3WORD,
PPE_PKT_CNT_SIZE_5WORD,
};
/**
* enum ppe_cnt_type - PPE counter type.
* @PPE_CNT_BM: Packet counter processed by BM.
* @PPE_CNT_PARSE: Packet counter parsed on ingress.
* @PPE_CNT_PORT_RX: Packet counter on the ingress port.
* @PPE_CNT_VLAN_RX: VLAN packet counter received.
* @PPE_CNT_L2_FWD: Packet counter processed by L2 forwarding.
* @PPE_CNT_CPU_CODE: Packet counter marked with various CPU codes.
* @PPE_CNT_VLAN_TX: VLAN packet counter transmitted.
* @PPE_CNT_PORT_TX: Packet counter on the egress port.
* @PPE_CNT_QM: Packet counter processed by QM.
*/
enum ppe_cnt_type {
PPE_CNT_BM,
PPE_CNT_PARSE,
PPE_CNT_PORT_RX,
PPE_CNT_VLAN_RX,
PPE_CNT_L2_FWD,
PPE_CNT_CPU_CODE,
PPE_CNT_VLAN_TX,
PPE_CNT_PORT_TX,
PPE_CNT_QM,
};
/**
* struct ppe_debugfs_entry - PPE debugfs entry.
* @name: Debugfs file name.
* @counter_type: PPE packet counter type.
* @ppe: PPE device.
*
* The PPE debugfs entry is used to create the debugfs file and passed
* to debugfs_create_file() as private data.
*/
struct ppe_debugfs_entry {
const char *name;
enum ppe_cnt_type counter_type;
struct ppe_device *ppe;
};
static const struct ppe_debugfs_entry debugfs_files[] = {
{
.name = "bm",
.counter_type = PPE_CNT_BM,
},
{
.name = "parse",
.counter_type = PPE_CNT_PARSE,
},
{
.name = "port_rx",
.counter_type = PPE_CNT_PORT_RX,
},
{
.name = "vlan_rx",
.counter_type = PPE_CNT_VLAN_RX,
},
{
.name = "l2_forward",
.counter_type = PPE_CNT_L2_FWD,
},
{
.name = "cpu_code",
.counter_type = PPE_CNT_CPU_CODE,
},
{
.name = "vlan_tx",
.counter_type = PPE_CNT_VLAN_TX,
},
{
.name = "port_tx",
.counter_type = PPE_CNT_PORT_TX,
},
{
.name = "qm",
.counter_type = PPE_CNT_QM,
},
};
static int ppe_pkt_cnt_get(struct ppe_device *ppe_dev, u32 reg,
enum ppe_cnt_size_type cnt_type,
u32 *cnt, u32 *drop_cnt)
{
u32 drop_pkt_cnt[PPE_DROP_PKT_CNT_TBL_SIZE];
u32 pkt_cnt[PPE_PKT_CNT_TBL_SIZE];
u32 value;
int ret;
switch (cnt_type) {
case PPE_PKT_CNT_SIZE_1WORD:
ret = regmap_read(ppe_dev->regmap, reg, &value);
if (ret)
return ret;
*cnt = value;
break;
case PPE_PKT_CNT_SIZE_3WORD:
ret = regmap_bulk_read(ppe_dev->regmap, reg,
pkt_cnt, ARRAY_SIZE(pkt_cnt));
if (ret)
return ret;
*cnt = PPE_GET_PKT_CNT(pkt_cnt);
break;
case PPE_PKT_CNT_SIZE_5WORD:
ret = regmap_bulk_read(ppe_dev->regmap, reg,
drop_pkt_cnt, ARRAY_SIZE(drop_pkt_cnt));
if (ret)
return ret;
*cnt = PPE_GET_PKT_CNT(drop_pkt_cnt);
/* Drop counter with low 24 bits. */
value = PPE_GET_DROP_PKT_CNT_LOW(drop_pkt_cnt);
*drop_cnt = FIELD_PREP(GENMASK(23, 0), value);
/* Drop counter with high 8 bits. */
value = PPE_GET_DROP_PKT_CNT_HIGH(drop_pkt_cnt);
*drop_cnt |= FIELD_PREP(GENMASK(31, 24), value);
break;
}
return 0;
}
static void ppe_tbl_pkt_cnt_clear(struct ppe_device *ppe_dev, u32 reg,
enum ppe_cnt_size_type cnt_type)
{
u32 drop_pkt_cnt[PPE_DROP_PKT_CNT_TBL_SIZE] = {};
u32 pkt_cnt[PPE_PKT_CNT_TBL_SIZE] = {};
switch (cnt_type) {
case PPE_PKT_CNT_SIZE_1WORD:
regmap_write(ppe_dev->regmap, reg, 0);
break;
case PPE_PKT_CNT_SIZE_3WORD:
regmap_bulk_write(ppe_dev->regmap, reg,
pkt_cnt, ARRAY_SIZE(pkt_cnt));
break;
case PPE_PKT_CNT_SIZE_5WORD:
regmap_bulk_write(ppe_dev->regmap, reg,
drop_pkt_cnt, ARRAY_SIZE(drop_pkt_cnt));
break;
}
}
static int ppe_bm_counter_get(struct ppe_device *ppe_dev, struct seq_file *seq)
{
u32 reg, val, pkt_cnt, pkt_cnt1;
int ret, i, tag;
seq_printf(seq, "%-24s", "BM SILENT_DROP:");
tag = 0;
for (i = 0; i < PPE_DROP_CNT_TBL_ENTRIES; i++) {
reg = PPE_DROP_CNT_TBL_ADDR + i * PPE_DROP_CNT_TBL_INC;
ret = ppe_pkt_cnt_get(ppe_dev, reg, PPE_PKT_CNT_SIZE_1WORD,
&pkt_cnt, NULL);
if (ret) {
dev_err(ppe_dev->dev, "CNT ERROR %d\n", ret);
return ret;
}
if (pkt_cnt > 0) {
if (!((++tag) % 4))
seq_printf(seq, "\n%-24s", "");
seq_printf(seq, "%10u(%s=%04d)", pkt_cnt, "port", i);
}
}
seq_putc(seq, '\n');
/* The number of packets dropped because hardware buffers were
* available only partially for the packet.
*/
seq_printf(seq, "%-24s", "BM OVERFLOW_DROP:");
tag = 0;
for (i = 0; i < PPE_DROP_STAT_TBL_ENTRIES; i++) {
reg = PPE_DROP_STAT_TBL_ADDR + PPE_DROP_STAT_TBL_INC * i;
ret = ppe_pkt_cnt_get(ppe_dev, reg, PPE_PKT_CNT_SIZE_3WORD,
&pkt_cnt, NULL);
if (ret) {
dev_err(ppe_dev->dev, "CNT ERROR %d\n", ret);
return ret;
}
if (pkt_cnt > 0) {
if (!((++tag) % 4))
seq_printf(seq, "\n%-24s", "");
seq_printf(seq, "%10u(%s=%04d)", pkt_cnt, "port", i);
}
}
seq_putc(seq, '\n');
/* The number of currently occupied buffers, that can't be flushed. */
seq_printf(seq, "%-24s", "BM USED/REACT:");
tag = 0;
for (i = 0; i < PPE_BM_USED_CNT_TBL_ENTRIES; i++) {
reg = PPE_BM_USED_CNT_TBL_ADDR + i * PPE_BM_USED_CNT_TBL_INC;
ret = regmap_read(ppe_dev->regmap, reg, &val);
if (ret) {
dev_err(ppe_dev->dev, "CNT ERROR %d\n", ret);
return ret;
}
/* The number of PPE buffers used for caching the received
* packets before the pause frame sent.
*/
pkt_cnt = FIELD_GET(PPE_BM_USED_CNT_VAL, val);
reg = PPE_BM_REACT_CNT_TBL_ADDR + i * PPE_BM_REACT_CNT_TBL_INC;
ret = regmap_read(ppe_dev->regmap, reg, &val);
if (ret) {
dev_err(ppe_dev->dev, "CNT ERROR %d\n", ret);
return ret;
}
/* The number of PPE buffers used for caching the received
* packets after pause frame sent out.
*/
pkt_cnt1 = FIELD_GET(PPE_BM_REACT_CNT_VAL, val);
if (pkt_cnt > 0 || pkt_cnt1 > 0) {
if (!((++tag) % 4))
seq_printf(seq, "\n%-24s", "");
seq_printf(seq, "%10u/%u(%s=%04d)", pkt_cnt, pkt_cnt1,
"port", i);
}
}
seq_putc(seq, '\n');
return 0;
}
/* The number of packets processed by the ingress parser module of PPE. */
static int ppe_parse_pkt_counter_get(struct ppe_device *ppe_dev,
struct seq_file *seq)
{
u32 reg, cnt = 0, tunnel_cnt = 0;
int i, ret, tag = 0;
seq_printf(seq, "%-24s", "PARSE TPRX/IPRX:");
for (i = 0; i < PPE_IPR_PKT_CNT_TBL_ENTRIES; i++) {
reg = PPE_TPR_PKT_CNT_TBL_ADDR + i * PPE_TPR_PKT_CNT_TBL_INC;
ret = ppe_pkt_cnt_get(ppe_dev, reg, PPE_PKT_CNT_SIZE_1WORD,
&tunnel_cnt, NULL);
if (ret) {
dev_err(ppe_dev->dev, "CNT ERROR %d\n", ret);
return ret;
}
reg = PPE_IPR_PKT_CNT_TBL_ADDR + i * PPE_IPR_PKT_CNT_TBL_INC;
ret = ppe_pkt_cnt_get(ppe_dev, reg, PPE_PKT_CNT_SIZE_1WORD,
&cnt, NULL);
if (ret) {
dev_err(ppe_dev->dev, "CNT ERROR %d\n", ret);
return ret;
}
if (tunnel_cnt > 0 || cnt > 0) {
if (!((++tag) % 4))
seq_printf(seq, "\n%-24s", "");
seq_printf(seq, "%10u/%u(%s=%04d)", tunnel_cnt, cnt,
"port", i);
}
}
seq_putc(seq, '\n');
return 0;
}
/* The number of packets received or dropped on the ingress port. */
static int ppe_port_rx_counter_get(struct ppe_device *ppe_dev,
struct seq_file *seq)
{
u32 reg, pkt_cnt = 0, drop_cnt = 0;
int ret, i, tag;
seq_printf(seq, "%-24s", "PORT RX/RX_DROP:");
tag = 0;
for (i = 0; i < PPE_PHY_PORT_RX_CNT_TBL_ENTRIES; i++) {
reg = PPE_PHY_PORT_RX_CNT_TBL_ADDR + PPE_PHY_PORT_RX_CNT_TBL_INC * i;
ret = ppe_pkt_cnt_get(ppe_dev, reg, PPE_PKT_CNT_SIZE_5WORD,
&pkt_cnt, &drop_cnt);
if (ret) {
dev_err(ppe_dev->dev, "CNT ERROR %d\n", ret);
return ret;
}
if (pkt_cnt > 0) {
if (!((++tag) % 4))
seq_printf(seq, "\n%-24s", "");
seq_printf(seq, "%10u/%u(%s=%04d)", pkt_cnt, drop_cnt,
"port", i);
}
}
seq_putc(seq, '\n');
seq_printf(seq, "%-24s", "VPORT RX/RX_DROP:");
tag = 0;
for (i = 0; i < PPE_PORT_RX_CNT_TBL_ENTRIES; i++) {
reg = PPE_PORT_RX_CNT_TBL_ADDR + PPE_PORT_RX_CNT_TBL_INC * i;
ret = ppe_pkt_cnt_get(ppe_dev, reg, PPE_PKT_CNT_SIZE_5WORD,
&pkt_cnt, &drop_cnt);
if (ret) {
dev_err(ppe_dev->dev, "CNT ERROR %d\n", ret);
return ret;
}
if (pkt_cnt > 0) {
if (!((++tag) % 4))
seq_printf(seq, "\n%-24s", "");
seq_printf(seq, "%10u/%u(%s=%04d)", pkt_cnt, drop_cnt,
"port", i);
}
}
seq_putc(seq, '\n');
return 0;
}
/* The number of packets received or dropped by layer 2 processing. */
static int ppe_l2_counter_get(struct ppe_device *ppe_dev,
struct seq_file *seq)
{
u32 reg, pkt_cnt = 0, drop_cnt = 0;
int ret, i, tag = 0;
seq_printf(seq, "%-24s", "L2 RX/RX_DROP:");
for (i = 0; i < PPE_PRE_L2_CNT_TBL_ENTRIES; i++) {
reg = PPE_PRE_L2_CNT_TBL_ADDR + PPE_PRE_L2_CNT_TBL_INC * i;
ret = ppe_pkt_cnt_get(ppe_dev, reg, PPE_PKT_CNT_SIZE_5WORD,
&pkt_cnt, &drop_cnt);
if (ret) {
dev_err(ppe_dev->dev, "CNT ERROR %d\n", ret);
return ret;
}
if (pkt_cnt > 0) {
if (!((++tag) % 4))
seq_printf(seq, "\n%-24s", "");
seq_printf(seq, "%10u/%u(%s=%04d)", pkt_cnt, drop_cnt,
"vsi", i);
}
}
seq_putc(seq, '\n');
return 0;
}
/* The number of VLAN packets received by PPE. */
static int ppe_vlan_rx_counter_get(struct ppe_device *ppe_dev,
struct seq_file *seq)
{
u32 reg, pkt_cnt = 0;
int ret, i, tag = 0;
seq_printf(seq, "%-24s", "VLAN RX:");
for (i = 0; i < PPE_VLAN_CNT_TBL_ENTRIES; i++) {
reg = PPE_VLAN_CNT_TBL_ADDR + PPE_VLAN_CNT_TBL_INC * i;
ret = ppe_pkt_cnt_get(ppe_dev, reg, PPE_PKT_CNT_SIZE_3WORD,
&pkt_cnt, NULL);
if (ret) {
dev_err(ppe_dev->dev, "CNT ERROR %d\n", ret);
return ret;
}
if (pkt_cnt > 0) {
if (!((++tag) % 4))
seq_printf(seq, "\n%-24s", "");
seq_printf(seq, "%10u(%s=%04d)", pkt_cnt, "vsi", i);
}
}
seq_putc(seq, '\n');
return 0;
}
/* The number of packets handed to CPU by PPE. */
static int ppe_cpu_code_counter_get(struct ppe_device *ppe_dev,
struct seq_file *seq)
{
u32 reg, pkt_cnt = 0;
int ret, i;
seq_printf(seq, "%-24s", "CPU CODE:");
for (i = 0; i < PPE_DROP_CPU_CNT_TBL_ENTRIES; i++) {
reg = PPE_DROP_CPU_CNT_TBL_ADDR + PPE_DROP_CPU_CNT_TBL_INC * i;
ret = ppe_pkt_cnt_get(ppe_dev, reg, PPE_PKT_CNT_SIZE_3WORD,
&pkt_cnt, NULL);
if (ret) {
dev_err(ppe_dev->dev, "CNT ERROR %d\n", ret);
return ret;
}
if (!pkt_cnt)
continue;
/* There are 256 CPU codes saved in the first 256 entries
* of register table, and 128 drop codes for each PPE port
* (0-7), the total entries is 256 + 8 * 128.
*/
if (i < 256)
seq_printf(seq, "%10u(cpucode:%d)", pkt_cnt, i);
else
seq_printf(seq, "%10u(port=%04d),dropcode:%d", pkt_cnt,
(i - 256) % 8, (i - 256) / 8);
seq_putc(seq, '\n');
seq_printf(seq, "%-24s", "");
}
seq_putc(seq, '\n');
return 0;
}
/* The number of packets forwarded by VLAN on the egress direction. */
static int ppe_vlan_tx_counter_get(struct ppe_device *ppe_dev,
struct seq_file *seq)
{
u32 reg, pkt_cnt = 0;
int ret, i, tag = 0;
seq_printf(seq, "%-24s", "VLAN TX:");
for (i = 0; i < PPE_EG_VSI_COUNTER_TBL_ENTRIES; i++) {
reg = PPE_EG_VSI_COUNTER_TBL_ADDR + PPE_EG_VSI_COUNTER_TBL_INC * i;
ret = ppe_pkt_cnt_get(ppe_dev, reg, PPE_PKT_CNT_SIZE_3WORD,
&pkt_cnt, NULL);
if (ret) {
dev_err(ppe_dev->dev, "CNT ERROR %d\n", ret);
return ret;
}
if (pkt_cnt > 0) {
if (!((++tag) % 4))
seq_printf(seq, "\n%-24s", "");
seq_printf(seq, "%10u(%s=%04d)", pkt_cnt, "vsi", i);
}
}
seq_putc(seq, '\n');
return 0;
}
/* The number of packets transmitted or dropped on the egress port. */
static int ppe_port_tx_counter_get(struct ppe_device *ppe_dev,
struct seq_file *seq)
{
u32 reg, pkt_cnt = 0, drop_cnt = 0;
int ret, i, tag;
seq_printf(seq, "%-24s", "VPORT TX/TX_DROP:");
tag = 0;
for (i = 0; i < PPE_VPORT_TX_COUNTER_TBL_ENTRIES; i++) {
reg = PPE_VPORT_TX_COUNTER_TBL_ADDR + PPE_VPORT_TX_COUNTER_TBL_INC * i;
ret = ppe_pkt_cnt_get(ppe_dev, reg, PPE_PKT_CNT_SIZE_3WORD,
&pkt_cnt, NULL);
if (ret) {
dev_err(ppe_dev->dev, "CNT ERROR %d\n", ret);
return ret;
}
reg = PPE_VPORT_TX_DROP_CNT_TBL_ADDR + PPE_VPORT_TX_DROP_CNT_TBL_INC * i;
ret = ppe_pkt_cnt_get(ppe_dev, reg, PPE_PKT_CNT_SIZE_3WORD,
&drop_cnt, NULL);
if (ret) {
dev_err(ppe_dev->dev, "CNT ERROR %d\n", ret);
return ret;
}
if (pkt_cnt > 0 || drop_cnt > 0) {
if (!((++tag) % 4))
seq_printf(seq, "\n%-24s", "");
seq_printf(seq, "%10u/%u(%s=%04d)", pkt_cnt, drop_cnt,
"port", i);
}
}
seq_putc(seq, '\n');
seq_printf(seq, "%-24s", "PORT TX/TX_DROP:");
tag = 0;
for (i = 0; i < PPE_PORT_TX_COUNTER_TBL_ENTRIES; i++) {
reg = PPE_PORT_TX_COUNTER_TBL_ADDR + PPE_PORT_TX_COUNTER_TBL_INC * i;
ret = ppe_pkt_cnt_get(ppe_dev, reg, PPE_PKT_CNT_SIZE_3WORD,
&pkt_cnt, NULL);
if (ret) {
dev_err(ppe_dev->dev, "CNT ERROR %d\n", ret);
return ret;
}
reg = PPE_PORT_TX_DROP_CNT_TBL_ADDR + PPE_PORT_TX_DROP_CNT_TBL_INC * i;
ret = ppe_pkt_cnt_get(ppe_dev, reg, PPE_PKT_CNT_SIZE_3WORD,
&drop_cnt, NULL);
if (ret) {
dev_err(ppe_dev->dev, "CNT ERROR %d\n", ret);
return ret;
}
if (pkt_cnt > 0 || drop_cnt > 0) {
if (!((++tag) % 4))
seq_printf(seq, "\n%-24s", "");
seq_printf(seq, "%10u/%u(%s=%04d)", pkt_cnt, drop_cnt,
"port", i);
}
}
seq_putc(seq, '\n');
return 0;
}
/* The number of packets transmitted or pending by the PPE queue. */
static int ppe_queue_counter_get(struct ppe_device *ppe_dev,
struct seq_file *seq)
{
u32 reg, val, pkt_cnt = 0, pend_cnt = 0, drop_cnt = 0;
int ret, i, tag = 0;
seq_printf(seq, "%-24s", "QUEUE TX/PEND/DROP:");
for (i = 0; i < PPE_QUEUE_TX_COUNTER_TBL_ENTRIES; i++) {
reg = PPE_QUEUE_TX_COUNTER_TBL_ADDR + PPE_QUEUE_TX_COUNTER_TBL_INC * i;
ret = ppe_pkt_cnt_get(ppe_dev, reg, PPE_PKT_CNT_SIZE_3WORD,
&pkt_cnt, NULL);
if (ret) {
dev_err(ppe_dev->dev, "CNT ERROR %d\n", ret);
return ret;
}
if (i < PPE_AC_UNICAST_QUEUE_CFG_TBL_ENTRIES) {
reg = PPE_AC_UNICAST_QUEUE_CNT_TBL_ADDR +
PPE_AC_UNICAST_QUEUE_CNT_TBL_INC * i;
ret = regmap_read(ppe_dev->regmap, reg, &val);
if (ret) {
dev_err(ppe_dev->dev, "CNT ERROR %d\n", ret);
return ret;
}
pend_cnt = FIELD_GET(PPE_AC_UNICAST_QUEUE_CNT_TBL_PEND_CNT, val);
reg = PPE_UNICAST_DROP_CNT_TBL_ADDR +
PPE_AC_UNICAST_QUEUE_CNT_TBL_INC *
(i * PPE_UNICAST_DROP_TYPES + PPE_UNICAST_DROP_FORCE_OFFSET);
ret = ppe_pkt_cnt_get(ppe_dev, reg, PPE_PKT_CNT_SIZE_3WORD,
&drop_cnt, NULL);
if (ret) {
dev_err(ppe_dev->dev, "CNT ERROR %d\n", ret);
return ret;
}
} else {
int mq_offset = i - PPE_AC_UNICAST_QUEUE_CFG_TBL_ENTRIES;
reg = PPE_AC_MULTICAST_QUEUE_CNT_TBL_ADDR +
PPE_AC_MULTICAST_QUEUE_CNT_TBL_INC * mq_offset;
ret = regmap_read(ppe_dev->regmap, reg, &val);
if (ret) {
dev_err(ppe_dev->dev, "CNT ERROR %d\n", ret);
return ret;
}
pend_cnt = FIELD_GET(PPE_AC_MULTICAST_QUEUE_CNT_TBL_PEND_CNT, val);
if (mq_offset < PPE_P0_MULTICAST_QUEUE_NUM) {
reg = PPE_CPU_PORT_MULTICAST_FORCE_DROP_CNT_TBL_ADDR(mq_offset);
} else {
mq_offset -= PPE_P0_MULTICAST_QUEUE_NUM;
reg = PPE_P1_MULTICAST_DROP_CNT_TBL_ADDR;
reg += (mq_offset / PPE_MULTICAST_QUEUE_NUM) *
PPE_MULTICAST_QUEUE_PORT_ADDR_INC;
reg += (mq_offset % PPE_MULTICAST_QUEUE_NUM) *
PPE_MULTICAST_DROP_CNT_TBL_INC *
PPE_MULTICAST_DROP_TYPES;
}
ret = ppe_pkt_cnt_get(ppe_dev, reg, PPE_PKT_CNT_SIZE_3WORD,
&drop_cnt, NULL);
if (ret) {
dev_err(ppe_dev->dev, "CNT ERROR %d\n", ret);
return ret;
}
}
if (pkt_cnt > 0 || pend_cnt > 0 || drop_cnt > 0) {
if (!((++tag) % 4))
seq_printf(seq, "\n%-24s", "");
seq_printf(seq, "%10u/%u/%u(%s=%04d)",
pkt_cnt, pend_cnt, drop_cnt, "queue", i);
}
}
seq_putc(seq, '\n');
return 0;
}
/* Display the various packet counters of PPE. */
static int ppe_packet_counter_show(struct seq_file *seq, void *v)
{
struct ppe_debugfs_entry *entry = seq->private;
struct ppe_device *ppe_dev = entry->ppe;
int ret;
switch (entry->counter_type) {
case PPE_CNT_BM:
ret = ppe_bm_counter_get(ppe_dev, seq);
break;
case PPE_CNT_PARSE:
ret = ppe_parse_pkt_counter_get(ppe_dev, seq);
break;
case PPE_CNT_PORT_RX:
ret = ppe_port_rx_counter_get(ppe_dev, seq);
break;
case PPE_CNT_VLAN_RX:
ret = ppe_vlan_rx_counter_get(ppe_dev, seq);
break;
case PPE_CNT_L2_FWD:
ret = ppe_l2_counter_get(ppe_dev, seq);
break;
case PPE_CNT_CPU_CODE:
ret = ppe_cpu_code_counter_get(ppe_dev, seq);
break;
case PPE_CNT_VLAN_TX:
ret = ppe_vlan_tx_counter_get(ppe_dev, seq);
break;
case PPE_CNT_PORT_TX:
ret = ppe_port_tx_counter_get(ppe_dev, seq);
break;
case PPE_CNT_QM:
ret = ppe_queue_counter_get(ppe_dev, seq);
break;
default:
ret = -EINVAL;
break;
}
return ret;
}
/* Flush the various packet counters of PPE. */
static ssize_t ppe_packet_counter_write(struct file *file,
const char __user *buf,
size_t count, loff_t *pos)
{
struct ppe_debugfs_entry *entry = file_inode(file)->i_private;
struct ppe_device *ppe_dev = entry->ppe;
u32 reg;
int i;
switch (entry->counter_type) {
case PPE_CNT_BM:
for (i = 0; i < PPE_DROP_CNT_TBL_ENTRIES; i++) {
reg = PPE_DROP_CNT_TBL_ADDR + i * PPE_DROP_CNT_TBL_INC;
ppe_tbl_pkt_cnt_clear(ppe_dev, reg, PPE_PKT_CNT_SIZE_1WORD);
}
for (i = 0; i < PPE_DROP_STAT_TBL_ENTRIES; i++) {
reg = PPE_DROP_STAT_TBL_ADDR + PPE_DROP_STAT_TBL_INC * i;
ppe_tbl_pkt_cnt_clear(ppe_dev, reg, PPE_PKT_CNT_SIZE_3WORD);
}
break;
case PPE_CNT_PARSE:
for (i = 0; i < PPE_IPR_PKT_CNT_TBL_ENTRIES; i++) {
reg = PPE_IPR_PKT_CNT_TBL_ADDR + i * PPE_IPR_PKT_CNT_TBL_INC;
ppe_tbl_pkt_cnt_clear(ppe_dev, reg, PPE_PKT_CNT_SIZE_1WORD);
reg = PPE_TPR_PKT_CNT_TBL_ADDR + i * PPE_TPR_PKT_CNT_TBL_INC;
ppe_tbl_pkt_cnt_clear(ppe_dev, reg, PPE_PKT_CNT_SIZE_1WORD);
}
break;
case PPE_CNT_PORT_RX:
for (i = 0; i < PPE_PORT_RX_CNT_TBL_ENTRIES; i++) {
reg = PPE_PORT_RX_CNT_TBL_ADDR + PPE_PORT_RX_CNT_TBL_INC * i;
ppe_tbl_pkt_cnt_clear(ppe_dev, reg, PPE_PKT_CNT_SIZE_5WORD);
}
for (i = 0; i < PPE_PHY_PORT_RX_CNT_TBL_ENTRIES; i++) {
reg = PPE_PHY_PORT_RX_CNT_TBL_ADDR + PPE_PHY_PORT_RX_CNT_TBL_INC * i;
ppe_tbl_pkt_cnt_clear(ppe_dev, reg, PPE_PKT_CNT_SIZE_5WORD);
}
break;
case PPE_CNT_VLAN_RX:
for (i = 0; i < PPE_VLAN_CNT_TBL_ENTRIES; i++) {
reg = PPE_VLAN_CNT_TBL_ADDR + PPE_VLAN_CNT_TBL_INC * i;
ppe_tbl_pkt_cnt_clear(ppe_dev, reg, PPE_PKT_CNT_SIZE_3WORD);
}
break;
case PPE_CNT_L2_FWD:
for (i = 0; i < PPE_PRE_L2_CNT_TBL_ENTRIES; i++) {
reg = PPE_PRE_L2_CNT_TBL_ADDR + PPE_PRE_L2_CNT_TBL_INC * i;
ppe_tbl_pkt_cnt_clear(ppe_dev, reg, PPE_PKT_CNT_SIZE_5WORD);
}
break;
case PPE_CNT_CPU_CODE:
for (i = 0; i < PPE_DROP_CPU_CNT_TBL_ENTRIES; i++) {
reg = PPE_DROP_CPU_CNT_TBL_ADDR + PPE_DROP_CPU_CNT_TBL_INC * i;
ppe_tbl_pkt_cnt_clear(ppe_dev, reg, PPE_PKT_CNT_SIZE_3WORD);
}
break;
case PPE_CNT_VLAN_TX:
for (i = 0; i < PPE_EG_VSI_COUNTER_TBL_ENTRIES; i++) {
reg = PPE_EG_VSI_COUNTER_TBL_ADDR + PPE_EG_VSI_COUNTER_TBL_INC * i;
ppe_tbl_pkt_cnt_clear(ppe_dev, reg, PPE_PKT_CNT_SIZE_3WORD);
}
break;
case PPE_CNT_PORT_TX:
for (i = 0; i < PPE_PORT_TX_COUNTER_TBL_ENTRIES; i++) {
reg = PPE_PORT_TX_DROP_CNT_TBL_ADDR + PPE_PORT_TX_DROP_CNT_TBL_INC * i;
ppe_tbl_pkt_cnt_clear(ppe_dev, reg, PPE_PKT_CNT_SIZE_3WORD);
reg = PPE_PORT_TX_COUNTER_TBL_ADDR + PPE_PORT_TX_COUNTER_TBL_INC * i;
ppe_tbl_pkt_cnt_clear(ppe_dev, reg, PPE_PKT_CNT_SIZE_3WORD);
}
for (i = 0; i < PPE_VPORT_TX_COUNTER_TBL_ENTRIES; i++) {
reg = PPE_VPORT_TX_COUNTER_TBL_ADDR + PPE_VPORT_TX_COUNTER_TBL_INC * i;
ppe_tbl_pkt_cnt_clear(ppe_dev, reg, PPE_PKT_CNT_SIZE_3WORD);
reg = PPE_VPORT_TX_DROP_CNT_TBL_ADDR + PPE_VPORT_TX_DROP_CNT_TBL_INC * i;
ppe_tbl_pkt_cnt_clear(ppe_dev, reg, PPE_PKT_CNT_SIZE_3WORD);
}
break;
case PPE_CNT_QM:
for (i = 0; i < PPE_QUEUE_TX_COUNTER_TBL_ENTRIES; i++) {
reg = PPE_QUEUE_TX_COUNTER_TBL_ADDR + PPE_QUEUE_TX_COUNTER_TBL_INC * i;
ppe_tbl_pkt_cnt_clear(ppe_dev, reg, PPE_PKT_CNT_SIZE_3WORD);
}
break;
default:
break;
}
return count;
}
DEFINE_SHOW_STORE_ATTRIBUTE(ppe_packet_counter);
void ppe_debugfs_setup(struct ppe_device *ppe_dev)
{
struct ppe_debugfs_entry *entry;
int i;
ppe_dev->debugfs_root = debugfs_create_dir("ppe", NULL);
if (IS_ERR(ppe_dev->debugfs_root))
return;
for (i = 0; i < ARRAY_SIZE(debugfs_files); i++) {
entry = devm_kzalloc(ppe_dev->dev, sizeof(*entry), GFP_KERNEL);
if (!entry)
return;
entry->ppe = ppe_dev;
entry->counter_type = debugfs_files[i].counter_type;
debugfs_create_file(debugfs_files[i].name, 0444,
ppe_dev->debugfs_root, entry,
&ppe_packet_counter_fops);
}
}
void ppe_debugfs_teardown(struct ppe_device *ppe_dev)
{
debugfs_remove_recursive(ppe_dev->debugfs_root);
ppe_dev->debugfs_root = NULL;
}

View File

@ -0,0 +1,16 @@
/* SPDX-License-Identifier: GPL-2.0-only
*
* Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
*/
/* PPE debugfs counters setup. */
#ifndef __PPE_DEBUGFS_H__
#define __PPE_DEBUGFS_H__
#include "ppe.h"
void ppe_debugfs_setup(struct ppe_device *ppe_dev);
void ppe_debugfs_teardown(struct ppe_device *ppe_dev);
#endif

View File

@ -0,0 +1,591 @@
/* SPDX-License-Identifier: GPL-2.0-only
*
* Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
*/
/* PPE hardware register and table declarations. */
#ifndef __PPE_REGS_H__
#define __PPE_REGS_H__
#include <linux/bitfield.h>
/* PPE scheduler configurations for buffer manager block. */
#define PPE_BM_SCH_CTRL_ADDR 0xb000
#define PPE_BM_SCH_CTRL_INC 4
#define PPE_BM_SCH_CTRL_SCH_DEPTH GENMASK(7, 0)
#define PPE_BM_SCH_CTRL_SCH_OFFSET GENMASK(14, 8)
#define PPE_BM_SCH_CTRL_SCH_EN BIT(31)
/* PPE drop counters. */
#define PPE_DROP_CNT_TBL_ADDR 0xb024
#define PPE_DROP_CNT_TBL_ENTRIES 8
#define PPE_DROP_CNT_TBL_INC 4
/* BM port drop counters. */
#define PPE_DROP_STAT_TBL_ADDR 0xe000
#define PPE_DROP_STAT_TBL_ENTRIES 30
#define PPE_DROP_STAT_TBL_INC 0x10
/* Egress VLAN counters. */
#define PPE_EG_VSI_COUNTER_TBL_ADDR 0x41000
#define PPE_EG_VSI_COUNTER_TBL_ENTRIES 64
#define PPE_EG_VSI_COUNTER_TBL_INC 0x10
/* Port TX counters. */
#define PPE_PORT_TX_COUNTER_TBL_ADDR 0x45000
#define PPE_PORT_TX_COUNTER_TBL_ENTRIES 8
#define PPE_PORT_TX_COUNTER_TBL_INC 0x10
/* Virtual port TX counters. */
#define PPE_VPORT_TX_COUNTER_TBL_ADDR 0x47000
#define PPE_VPORT_TX_COUNTER_TBL_ENTRIES 256
#define PPE_VPORT_TX_COUNTER_TBL_INC 0x10
/* Queue counters. */
#define PPE_QUEUE_TX_COUNTER_TBL_ADDR 0x4a000
#define PPE_QUEUE_TX_COUNTER_TBL_ENTRIES 300
#define PPE_QUEUE_TX_COUNTER_TBL_INC 0x10
/* RSS settings are to calculate the random RSS hash value generated during
* packet receive to ARM cores. This hash is then used to generate the queue
* offset used to determine the queue used to transmit the packet to ARM cores.
*/
#define PPE_RSS_HASH_MASK_ADDR 0xb4318
#define PPE_RSS_HASH_MASK_HASH_MASK GENMASK(20, 0)
#define PPE_RSS_HASH_MASK_FRAGMENT BIT(28)
#define PPE_RSS_HASH_SEED_ADDR 0xb431c
#define PPE_RSS_HASH_SEED_VAL GENMASK(31, 0)
#define PPE_RSS_HASH_MIX_ADDR 0xb4320
#define PPE_RSS_HASH_MIX_ENTRIES 11
#define PPE_RSS_HASH_MIX_INC 4
#define PPE_RSS_HASH_MIX_VAL GENMASK(4, 0)
#define PPE_RSS_HASH_FIN_ADDR 0xb4350
#define PPE_RSS_HASH_FIN_ENTRIES 5
#define PPE_RSS_HASH_FIN_INC 4
#define PPE_RSS_HASH_FIN_INNER GENMASK(4, 0)
#define PPE_RSS_HASH_FIN_OUTER GENMASK(9, 5)
#define PPE_RSS_HASH_MASK_IPV4_ADDR 0xb4380
#define PPE_RSS_HASH_MASK_IPV4_HASH_MASK GENMASK(20, 0)
#define PPE_RSS_HASH_MASK_IPV4_FRAGMENT BIT(28)
#define PPE_RSS_HASH_SEED_IPV4_ADDR 0xb4384
#define PPE_RSS_HASH_SEED_IPV4_VAL GENMASK(31, 0)
#define PPE_RSS_HASH_MIX_IPV4_ADDR 0xb4390
#define PPE_RSS_HASH_MIX_IPV4_ENTRIES 5
#define PPE_RSS_HASH_MIX_IPV4_INC 4
#define PPE_RSS_HASH_MIX_IPV4_VAL GENMASK(4, 0)
#define PPE_RSS_HASH_FIN_IPV4_ADDR 0xb43b0
#define PPE_RSS_HASH_FIN_IPV4_ENTRIES 5
#define PPE_RSS_HASH_FIN_IPV4_INC 4
#define PPE_RSS_HASH_FIN_IPV4_INNER GENMASK(4, 0)
#define PPE_RSS_HASH_FIN_IPV4_OUTER GENMASK(9, 5)
#define PPE_BM_SCH_CFG_TBL_ADDR 0xc000
#define PPE_BM_SCH_CFG_TBL_ENTRIES 128
#define PPE_BM_SCH_CFG_TBL_INC 0x10
#define PPE_BM_SCH_CFG_TBL_PORT_NUM GENMASK(3, 0)
#define PPE_BM_SCH_CFG_TBL_DIR BIT(4)
#define PPE_BM_SCH_CFG_TBL_VALID BIT(5)
#define PPE_BM_SCH_CFG_TBL_SECOND_PORT_VALID BIT(6)
#define PPE_BM_SCH_CFG_TBL_SECOND_PORT GENMASK(11, 8)
/* PPE service code configuration for the ingress direction functions,
* including bypass configuration for relevant PPE switch core functions
* such as flow entry lookup bypass.
*/
#define PPE_SERVICE_TBL_ADDR 0x15000
#define PPE_SERVICE_TBL_ENTRIES 256
#define PPE_SERVICE_TBL_INC 0x10
#define PPE_SERVICE_W0_BYPASS_BITMAP GENMASK(31, 0)
#define PPE_SERVICE_W1_RX_CNT_EN BIT(0)
#define PPE_SERVICE_SET_BYPASS_BITMAP(tbl_cfg, value) \
FIELD_MODIFY(PPE_SERVICE_W0_BYPASS_BITMAP, tbl_cfg, value)
#define PPE_SERVICE_SET_RX_CNT_EN(tbl_cfg, value) \
FIELD_MODIFY(PPE_SERVICE_W1_RX_CNT_EN, (tbl_cfg) + 0x1, value)
/* PPE port egress VLAN configurations. */
#define PPE_PORT_EG_VLAN_TBL_ADDR 0x20020
#define PPE_PORT_EG_VLAN_TBL_ENTRIES 8
#define PPE_PORT_EG_VLAN_TBL_INC 4
#define PPE_PORT_EG_VLAN_TBL_VLAN_TYPE BIT(0)
#define PPE_PORT_EG_VLAN_TBL_CTAG_MODE GENMASK(2, 1)
#define PPE_PORT_EG_VLAN_TBL_STAG_MODE GENMASK(4, 3)
#define PPE_PORT_EG_VLAN_TBL_VSI_TAG_MODE_EN BIT(5)
#define PPE_PORT_EG_VLAN_TBL_PCP_PROP_CMD BIT(6)
#define PPE_PORT_EG_VLAN_TBL_DEI_PROP_CMD BIT(7)
#define PPE_PORT_EG_VLAN_TBL_TX_COUNTING_EN BIT(8)
/* PPE queue counters enable/disable control. */
#define PPE_EG_BRIDGE_CONFIG_ADDR 0x20044
#define PPE_EG_BRIDGE_CONFIG_QUEUE_CNT_EN BIT(2)
/* PPE service code configuration on the egress direction. */
#define PPE_EG_SERVICE_TBL_ADDR 0x43000
#define PPE_EG_SERVICE_TBL_ENTRIES 256
#define PPE_EG_SERVICE_TBL_INC 0x10
#define PPE_EG_SERVICE_W0_UPDATE_ACTION GENMASK(31, 0)
#define PPE_EG_SERVICE_W1_NEXT_SERVCODE GENMASK(7, 0)
#define PPE_EG_SERVICE_W1_HW_SERVICE GENMASK(13, 8)
#define PPE_EG_SERVICE_W1_OFFSET_SEL BIT(14)
#define PPE_EG_SERVICE_W1_TX_CNT_EN BIT(15)
#define PPE_EG_SERVICE_SET_UPDATE_ACTION(tbl_cfg, value) \
FIELD_MODIFY(PPE_EG_SERVICE_W0_UPDATE_ACTION, tbl_cfg, value)
#define PPE_EG_SERVICE_SET_NEXT_SERVCODE(tbl_cfg, value) \
FIELD_MODIFY(PPE_EG_SERVICE_W1_NEXT_SERVCODE, (tbl_cfg) + 0x1, value)
#define PPE_EG_SERVICE_SET_HW_SERVICE(tbl_cfg, value) \
FIELD_MODIFY(PPE_EG_SERVICE_W1_HW_SERVICE, (tbl_cfg) + 0x1, value)
#define PPE_EG_SERVICE_SET_OFFSET_SEL(tbl_cfg, value) \
FIELD_MODIFY(PPE_EG_SERVICE_W1_OFFSET_SEL, (tbl_cfg) + 0x1, value)
#define PPE_EG_SERVICE_SET_TX_CNT_EN(tbl_cfg, value) \
FIELD_MODIFY(PPE_EG_SERVICE_W1_TX_CNT_EN, (tbl_cfg) + 0x1, value)
/* PPE port bridge configuration */
#define PPE_PORT_BRIDGE_CTRL_ADDR 0x60300
#define PPE_PORT_BRIDGE_CTRL_ENTRIES 8
#define PPE_PORT_BRIDGE_CTRL_INC 4
#define PPE_PORT_BRIDGE_NEW_LRN_EN BIT(0)
#define PPE_PORT_BRIDGE_STA_MOVE_LRN_EN BIT(3)
#define PPE_PORT_BRIDGE_TXMAC_EN BIT(16)
/* PPE port control configurations for the traffic to the multicast queues. */
#define PPE_MC_MTU_CTRL_TBL_ADDR 0x60a00
#define PPE_MC_MTU_CTRL_TBL_ENTRIES 8
#define PPE_MC_MTU_CTRL_TBL_INC 4
#define PPE_MC_MTU_CTRL_TBL_MTU GENMASK(13, 0)
#define PPE_MC_MTU_CTRL_TBL_MTU_CMD GENMASK(15, 14)
#define PPE_MC_MTU_CTRL_TBL_TX_CNT_EN BIT(16)
/* PPE VSI configurations */
#define PPE_VSI_TBL_ADDR 0x63800
#define PPE_VSI_TBL_ENTRIES 64
#define PPE_VSI_TBL_INC 0x10
#define PPE_VSI_W0_MEMBER_PORT_BITMAP GENMASK(7, 0)
#define PPE_VSI_W0_UUC_BITMAP GENMASK(15, 8)
#define PPE_VSI_W0_UMC_BITMAP GENMASK(23, 16)
#define PPE_VSI_W0_BC_BITMAP GENMASK(31, 24)
#define PPE_VSI_W1_NEW_ADDR_LRN_EN BIT(0)
#define PPE_VSI_W1_NEW_ADDR_FWD_CMD GENMASK(2, 1)
#define PPE_VSI_W1_STATION_MOVE_LRN_EN BIT(3)
#define PPE_VSI_W1_STATION_MOVE_FWD_CMD GENMASK(5, 4)
#define PPE_VSI_SET_MEMBER_PORT_BITMAP(tbl_cfg, value) \
FIELD_MODIFY(PPE_VSI_W0_MEMBER_PORT_BITMAP, tbl_cfg, value)
#define PPE_VSI_SET_UUC_BITMAP(tbl_cfg, value) \
FIELD_MODIFY(PPE_VSI_W0_UUC_BITMAP, tbl_cfg, value)
#define PPE_VSI_SET_UMC_BITMAP(tbl_cfg, value) \
FIELD_MODIFY(PPE_VSI_W0_UMC_BITMAP, tbl_cfg, value)
#define PPE_VSI_SET_BC_BITMAP(tbl_cfg, value) \
FIELD_MODIFY(PPE_VSI_W0_BC_BITMAP, tbl_cfg, value)
#define PPE_VSI_SET_NEW_ADDR_LRN_EN(tbl_cfg, value) \
FIELD_MODIFY(PPE_VSI_W1_NEW_ADDR_LRN_EN, (tbl_cfg) + 0x1, value)
#define PPE_VSI_SET_NEW_ADDR_FWD_CMD(tbl_cfg, value) \
FIELD_MODIFY(PPE_VSI_W1_NEW_ADDR_FWD_CMD, (tbl_cfg) + 0x1, value)
#define PPE_VSI_SET_STATION_MOVE_LRN_EN(tbl_cfg, value) \
FIELD_MODIFY(PPE_VSI_W1_STATION_MOVE_LRN_EN, (tbl_cfg) + 0x1, value)
#define PPE_VSI_SET_STATION_MOVE_FWD_CMD(tbl_cfg, value) \
FIELD_MODIFY(PPE_VSI_W1_STATION_MOVE_FWD_CMD, (tbl_cfg) + 0x1, value)
/* PPE port control configurations for the traffic to the unicast queues. */
#define PPE_MRU_MTU_CTRL_TBL_ADDR 0x65000
#define PPE_MRU_MTU_CTRL_TBL_ENTRIES 256
#define PPE_MRU_MTU_CTRL_TBL_INC 0x10
#define PPE_MRU_MTU_CTRL_W0_MRU GENMASK(13, 0)
#define PPE_MRU_MTU_CTRL_W0_MRU_CMD GENMASK(15, 14)
#define PPE_MRU_MTU_CTRL_W0_MTU GENMASK(29, 16)
#define PPE_MRU_MTU_CTRL_W0_MTU_CMD GENMASK(31, 30)
#define PPE_MRU_MTU_CTRL_W1_RX_CNT_EN BIT(0)
#define PPE_MRU_MTU_CTRL_W1_TX_CNT_EN BIT(1)
#define PPE_MRU_MTU_CTRL_W1_SRC_PROFILE GENMASK(3, 2)
#define PPE_MRU_MTU_CTRL_W1_INNER_PREC_LOW BIT(31)
#define PPE_MRU_MTU_CTRL_W2_INNER_PREC_HIGH GENMASK(1, 0)
#define PPE_MRU_MTU_CTRL_SET_MRU(tbl_cfg, value) \
FIELD_MODIFY(PPE_MRU_MTU_CTRL_W0_MRU, tbl_cfg, value)
#define PPE_MRU_MTU_CTRL_SET_MRU_CMD(tbl_cfg, value) \
FIELD_MODIFY(PPE_MRU_MTU_CTRL_W0_MRU_CMD, tbl_cfg, value)
#define PPE_MRU_MTU_CTRL_SET_MTU(tbl_cfg, value) \
FIELD_MODIFY(PPE_MRU_MTU_CTRL_W0_MTU, tbl_cfg, value)
#define PPE_MRU_MTU_CTRL_SET_MTU_CMD(tbl_cfg, value) \
FIELD_MODIFY(PPE_MRU_MTU_CTRL_W0_MTU_CMD, tbl_cfg, value)
#define PPE_MRU_MTU_CTRL_SET_RX_CNT_EN(tbl_cfg, value) \
FIELD_MODIFY(PPE_MRU_MTU_CTRL_W1_RX_CNT_EN, (tbl_cfg) + 0x1, value)
#define PPE_MRU_MTU_CTRL_SET_TX_CNT_EN(tbl_cfg, value) \
FIELD_MODIFY(PPE_MRU_MTU_CTRL_W1_TX_CNT_EN, (tbl_cfg) + 0x1, value)
/* PPE service code configuration for destination port and counter. */
#define PPE_IN_L2_SERVICE_TBL_ADDR 0x66000
#define PPE_IN_L2_SERVICE_TBL_ENTRIES 256
#define PPE_IN_L2_SERVICE_TBL_INC 0x10
#define PPE_IN_L2_SERVICE_TBL_DST_PORT_ID_VALID BIT(0)
#define PPE_IN_L2_SERVICE_TBL_DST_PORT_ID GENMASK(4, 1)
#define PPE_IN_L2_SERVICE_TBL_DST_DIRECTION BIT(5)
#define PPE_IN_L2_SERVICE_TBL_DST_BYPASS_BITMAP GENMASK(29, 6)
#define PPE_IN_L2_SERVICE_TBL_RX_CNT_EN BIT(30)
#define PPE_IN_L2_SERVICE_TBL_TX_CNT_EN BIT(31)
/* L2 Port configurations */
#define PPE_L2_VP_PORT_TBL_ADDR 0x98000
#define PPE_L2_VP_PORT_TBL_ENTRIES 256
#define PPE_L2_VP_PORT_TBL_INC 0x10
#define PPE_L2_VP_PORT_W0_INVALID_VSI_FWD_EN BIT(0)
#define PPE_L2_VP_PORT_W0_DST_INFO GENMASK(9, 2)
#define PPE_L2_PORT_SET_INVALID_VSI_FWD_EN(tbl_cfg, value) \
FIELD_MODIFY(PPE_L2_VP_PORT_W0_INVALID_VSI_FWD_EN, tbl_cfg, value)
#define PPE_L2_PORT_SET_DST_INFO(tbl_cfg, value) \
FIELD_MODIFY(PPE_L2_VP_PORT_W0_DST_INFO, tbl_cfg, value)
/* Port RX and RX drop counters. */
#define PPE_PORT_RX_CNT_TBL_ADDR 0x150000
#define PPE_PORT_RX_CNT_TBL_ENTRIES 256
#define PPE_PORT_RX_CNT_TBL_INC 0x20
/* Physical port RX and RX drop counters. */
#define PPE_PHY_PORT_RX_CNT_TBL_ADDR 0x156000
#define PPE_PHY_PORT_RX_CNT_TBL_ENTRIES 8
#define PPE_PHY_PORT_RX_CNT_TBL_INC 0x20
/* Counters for the packet to CPU port. */
#define PPE_DROP_CPU_CNT_TBL_ADDR 0x160000
#define PPE_DROP_CPU_CNT_TBL_ENTRIES 1280
#define PPE_DROP_CPU_CNT_TBL_INC 0x10
/* VLAN counters. */
#define PPE_VLAN_CNT_TBL_ADDR 0x178000
#define PPE_VLAN_CNT_TBL_ENTRIES 64
#define PPE_VLAN_CNT_TBL_INC 0x10
/* PPE L2 counters. */
#define PPE_PRE_L2_CNT_TBL_ADDR 0x17c000
#define PPE_PRE_L2_CNT_TBL_ENTRIES 64
#define PPE_PRE_L2_CNT_TBL_INC 0x20
/* Port TX drop counters. */
#define PPE_PORT_TX_DROP_CNT_TBL_ADDR 0x17d000
#define PPE_PORT_TX_DROP_CNT_TBL_ENTRIES 8
#define PPE_PORT_TX_DROP_CNT_TBL_INC 0x10
/* Virtual port TX counters. */
#define PPE_VPORT_TX_DROP_CNT_TBL_ADDR 0x17e000
#define PPE_VPORT_TX_DROP_CNT_TBL_ENTRIES 256
#define PPE_VPORT_TX_DROP_CNT_TBL_INC 0x10
/* Counters for the tunnel packet. */
#define PPE_TPR_PKT_CNT_TBL_ADDR 0x1d0080
#define PPE_TPR_PKT_CNT_TBL_ENTRIES 8
#define PPE_TPR_PKT_CNT_TBL_INC 4
/* Counters for the all packet received. */
#define PPE_IPR_PKT_CNT_TBL_ADDR 0x1e0080
#define PPE_IPR_PKT_CNT_TBL_ENTRIES 8
#define PPE_IPR_PKT_CNT_TBL_INC 4
/* PPE service code configuration for the tunnel packet. */
#define PPE_TL_SERVICE_TBL_ADDR 0x306000
#define PPE_TL_SERVICE_TBL_ENTRIES 256
#define PPE_TL_SERVICE_TBL_INC 4
#define PPE_TL_SERVICE_TBL_BYPASS_BITMAP GENMASK(31, 0)
/* Port scheduler global config. */
#define PPE_PSCH_SCH_DEPTH_CFG_ADDR 0x400000
#define PPE_PSCH_SCH_DEPTH_CFG_INC 4
#define PPE_PSCH_SCH_DEPTH_CFG_SCH_DEPTH GENMASK(7, 0)
/* PPE queue level scheduler configurations. */
#define PPE_L0_FLOW_MAP_TBL_ADDR 0x402000
#define PPE_L0_FLOW_MAP_TBL_ENTRIES 300
#define PPE_L0_FLOW_MAP_TBL_INC 0x10
#define PPE_L0_FLOW_MAP_TBL_FLOW_ID GENMASK(5, 0)
#define PPE_L0_FLOW_MAP_TBL_C_PRI GENMASK(8, 6)
#define PPE_L0_FLOW_MAP_TBL_E_PRI GENMASK(11, 9)
#define PPE_L0_FLOW_MAP_TBL_C_NODE_WT GENMASK(21, 12)
#define PPE_L0_FLOW_MAP_TBL_E_NODE_WT GENMASK(31, 22)
#define PPE_L0_C_FLOW_CFG_TBL_ADDR 0x404000
#define PPE_L0_C_FLOW_CFG_TBL_ENTRIES 512
#define PPE_L0_C_FLOW_CFG_TBL_INC 0x10
#define PPE_L0_C_FLOW_CFG_TBL_NODE_ID GENMASK(7, 0)
#define PPE_L0_C_FLOW_CFG_TBL_NODE_CREDIT_UNIT BIT(8)
#define PPE_L0_E_FLOW_CFG_TBL_ADDR 0x406000
#define PPE_L0_E_FLOW_CFG_TBL_ENTRIES 512
#define PPE_L0_E_FLOW_CFG_TBL_INC 0x10
#define PPE_L0_E_FLOW_CFG_TBL_NODE_ID GENMASK(7, 0)
#define PPE_L0_E_FLOW_CFG_TBL_NODE_CREDIT_UNIT BIT(8)
#define PPE_L0_FLOW_PORT_MAP_TBL_ADDR 0x408000
#define PPE_L0_FLOW_PORT_MAP_TBL_ENTRIES 300
#define PPE_L0_FLOW_PORT_MAP_TBL_INC 0x10
#define PPE_L0_FLOW_PORT_MAP_TBL_PORT_NUM GENMASK(3, 0)
#define PPE_L0_COMP_CFG_TBL_ADDR 0x428000
#define PPE_L0_COMP_CFG_TBL_ENTRIES 300
#define PPE_L0_COMP_CFG_TBL_INC 0x10
#define PPE_L0_COMP_CFG_TBL_SHAPER_METER_LEN GENMASK(1, 0)
#define PPE_L0_COMP_CFG_TBL_NODE_METER_LEN GENMASK(3, 2)
/* PPE queue to Ethernet DMA ring mapping table. */
#define PPE_RING_Q_MAP_TBL_ADDR 0x42a000
#define PPE_RING_Q_MAP_TBL_ENTRIES 24
#define PPE_RING_Q_MAP_TBL_INC 0x40
/* Table addresses for per-queue dequeue setting. */
#define PPE_DEQ_OPR_TBL_ADDR 0x430000
#define PPE_DEQ_OPR_TBL_ENTRIES 300
#define PPE_DEQ_OPR_TBL_INC 0x10
#define PPE_DEQ_OPR_TBL_DEQ_DISABLE BIT(0)
/* PPE flow level scheduler configurations. */
#define PPE_L1_FLOW_MAP_TBL_ADDR 0x440000
#define PPE_L1_FLOW_MAP_TBL_ENTRIES 64
#define PPE_L1_FLOW_MAP_TBL_INC 0x10
#define PPE_L1_FLOW_MAP_TBL_FLOW_ID GENMASK(3, 0)
#define PPE_L1_FLOW_MAP_TBL_C_PRI GENMASK(6, 4)
#define PPE_L1_FLOW_MAP_TBL_E_PRI GENMASK(9, 7)
#define PPE_L1_FLOW_MAP_TBL_C_NODE_WT GENMASK(19, 10)
#define PPE_L1_FLOW_MAP_TBL_E_NODE_WT GENMASK(29, 20)
#define PPE_L1_C_FLOW_CFG_TBL_ADDR 0x442000
#define PPE_L1_C_FLOW_CFG_TBL_ENTRIES 64
#define PPE_L1_C_FLOW_CFG_TBL_INC 0x10
#define PPE_L1_C_FLOW_CFG_TBL_NODE_ID GENMASK(5, 0)
#define PPE_L1_C_FLOW_CFG_TBL_NODE_CREDIT_UNIT BIT(6)
#define PPE_L1_E_FLOW_CFG_TBL_ADDR 0x444000
#define PPE_L1_E_FLOW_CFG_TBL_ENTRIES 64
#define PPE_L1_E_FLOW_CFG_TBL_INC 0x10
#define PPE_L1_E_FLOW_CFG_TBL_NODE_ID GENMASK(5, 0)
#define PPE_L1_E_FLOW_CFG_TBL_NODE_CREDIT_UNIT BIT(6)
#define PPE_L1_FLOW_PORT_MAP_TBL_ADDR 0x446000
#define PPE_L1_FLOW_PORT_MAP_TBL_ENTRIES 64
#define PPE_L1_FLOW_PORT_MAP_TBL_INC 0x10
#define PPE_L1_FLOW_PORT_MAP_TBL_PORT_NUM GENMASK(3, 0)
#define PPE_L1_COMP_CFG_TBL_ADDR 0x46a000
#define PPE_L1_COMP_CFG_TBL_ENTRIES 64
#define PPE_L1_COMP_CFG_TBL_INC 0x10
#define PPE_L1_COMP_CFG_TBL_SHAPER_METER_LEN GENMASK(1, 0)
#define PPE_L1_COMP_CFG_TBL_NODE_METER_LEN GENMASK(3, 2)
/* PPE port scheduler configurations for egress. */
#define PPE_PSCH_SCH_CFG_TBL_ADDR 0x47a000
#define PPE_PSCH_SCH_CFG_TBL_ENTRIES 128
#define PPE_PSCH_SCH_CFG_TBL_INC 0x10
#define PPE_PSCH_SCH_CFG_TBL_DES_PORT GENMASK(3, 0)
#define PPE_PSCH_SCH_CFG_TBL_ENS_PORT GENMASK(7, 4)
#define PPE_PSCH_SCH_CFG_TBL_ENS_PORT_BITMAP GENMASK(15, 8)
#define PPE_PSCH_SCH_CFG_TBL_DES_SECOND_PORT_EN BIT(16)
#define PPE_PSCH_SCH_CFG_TBL_DES_SECOND_PORT GENMASK(20, 17)
/* There are 15 BM ports and 4 BM groups supported by PPE.
* BM port (0-7) is for EDMA port 0, BM port (8-13) is for
* PPE physical port 1-6 and BM port 14 is for EIP port.
*/
#define PPE_BM_PORT_FC_MODE_ADDR 0x600100
#define PPE_BM_PORT_FC_MODE_ENTRIES 15
#define PPE_BM_PORT_FC_MODE_INC 0x4
#define PPE_BM_PORT_FC_MODE_EN BIT(0)
#define PPE_BM_PORT_GROUP_ID_ADDR 0x600180
#define PPE_BM_PORT_GROUP_ID_ENTRIES 15
#define PPE_BM_PORT_GROUP_ID_INC 0x4
#define PPE_BM_PORT_GROUP_ID_SHARED_GROUP_ID GENMASK(1, 0)
/* Counters for PPE buffers used for packets cached. */
#define PPE_BM_USED_CNT_TBL_ADDR 0x6001c0
#define PPE_BM_USED_CNT_TBL_ENTRIES 15
#define PPE_BM_USED_CNT_TBL_INC 0x4
#define PPE_BM_USED_CNT_VAL GENMASK(10, 0)
/* Counters for PPE buffers used for packets received after pause frame sent. */
#define PPE_BM_REACT_CNT_TBL_ADDR 0x600240
#define PPE_BM_REACT_CNT_TBL_ENTRIES 15
#define PPE_BM_REACT_CNT_TBL_INC 0x4
#define PPE_BM_REACT_CNT_VAL GENMASK(8, 0)
#define PPE_BM_SHARED_GROUP_CFG_ADDR 0x600290
#define PPE_BM_SHARED_GROUP_CFG_ENTRIES 4
#define PPE_BM_SHARED_GROUP_CFG_INC 0x4
#define PPE_BM_SHARED_GROUP_CFG_SHARED_LIMIT GENMASK(10, 0)
#define PPE_BM_PORT_FC_CFG_TBL_ADDR 0x601000
#define PPE_BM_PORT_FC_CFG_TBL_ENTRIES 15
#define PPE_BM_PORT_FC_CFG_TBL_INC 0x10
#define PPE_BM_PORT_FC_W0_REACT_LIMIT GENMASK(8, 0)
#define PPE_BM_PORT_FC_W0_RESUME_THRESHOLD GENMASK(17, 9)
#define PPE_BM_PORT_FC_W0_RESUME_OFFSET GENMASK(28, 18)
#define PPE_BM_PORT_FC_W0_CEILING_LOW GENMASK(31, 29)
#define PPE_BM_PORT_FC_W1_CEILING_HIGH GENMASK(7, 0)
#define PPE_BM_PORT_FC_W1_WEIGHT GENMASK(10, 8)
#define PPE_BM_PORT_FC_W1_DYNAMIC BIT(11)
#define PPE_BM_PORT_FC_W1_PRE_ALLOC GENMASK(22, 12)
#define PPE_BM_PORT_FC_SET_REACT_LIMIT(tbl_cfg, value) \
FIELD_MODIFY(PPE_BM_PORT_FC_W0_REACT_LIMIT, tbl_cfg, value)
#define PPE_BM_PORT_FC_SET_RESUME_THRESHOLD(tbl_cfg, value) \
FIELD_MODIFY(PPE_BM_PORT_FC_W0_RESUME_THRESHOLD, tbl_cfg, value)
#define PPE_BM_PORT_FC_SET_RESUME_OFFSET(tbl_cfg, value) \
FIELD_MODIFY(PPE_BM_PORT_FC_W0_RESUME_OFFSET, tbl_cfg, value)
#define PPE_BM_PORT_FC_SET_CEILING_LOW(tbl_cfg, value) \
FIELD_MODIFY(PPE_BM_PORT_FC_W0_CEILING_LOW, tbl_cfg, value)
#define PPE_BM_PORT_FC_SET_CEILING_HIGH(tbl_cfg, value) \
FIELD_MODIFY(PPE_BM_PORT_FC_W1_CEILING_HIGH, (tbl_cfg) + 0x1, value)
#define PPE_BM_PORT_FC_SET_WEIGHT(tbl_cfg, value) \
FIELD_MODIFY(PPE_BM_PORT_FC_W1_WEIGHT, (tbl_cfg) + 0x1, value)
#define PPE_BM_PORT_FC_SET_DYNAMIC(tbl_cfg, value) \
FIELD_MODIFY(PPE_BM_PORT_FC_W1_DYNAMIC, (tbl_cfg) + 0x1, value)
#define PPE_BM_PORT_FC_SET_PRE_ALLOC(tbl_cfg, value) \
FIELD_MODIFY(PPE_BM_PORT_FC_W1_PRE_ALLOC, (tbl_cfg) + 0x1, value)
/* The queue base configurations based on destination port,
* service code or CPU code.
*/
#define PPE_UCAST_QUEUE_MAP_TBL_ADDR 0x810000
#define PPE_UCAST_QUEUE_MAP_TBL_ENTRIES 3072
#define PPE_UCAST_QUEUE_MAP_TBL_INC 0x10
#define PPE_UCAST_QUEUE_MAP_TBL_PROFILE_ID GENMASK(3, 0)
#define PPE_UCAST_QUEUE_MAP_TBL_QUEUE_ID GENMASK(11, 4)
/* The queue offset configurations based on RSS hash value. */
#define PPE_UCAST_HASH_MAP_TBL_ADDR 0x830000
#define PPE_UCAST_HASH_MAP_TBL_ENTRIES 4096
#define PPE_UCAST_HASH_MAP_TBL_INC 0x10
#define PPE_UCAST_HASH_MAP_TBL_HASH GENMASK(7, 0)
/* The queue offset configurations based on PPE internal priority. */
#define PPE_UCAST_PRIORITY_MAP_TBL_ADDR 0x842000
#define PPE_UCAST_PRIORITY_MAP_TBL_ENTRIES 256
#define PPE_UCAST_PRIORITY_MAP_TBL_INC 0x10
#define PPE_UCAST_PRIORITY_MAP_TBL_CLASS GENMASK(3, 0)
/* PPE unicast queue (0-255) configurations. */
#define PPE_AC_UNICAST_QUEUE_CFG_TBL_ADDR 0x848000
#define PPE_AC_UNICAST_QUEUE_CFG_TBL_ENTRIES 256
#define PPE_AC_UNICAST_QUEUE_CFG_TBL_INC 0x10
#define PPE_AC_UNICAST_QUEUE_CFG_W0_EN BIT(0)
#define PPE_AC_UNICAST_QUEUE_CFG_W0_WRED_EN BIT(1)
#define PPE_AC_UNICAST_QUEUE_CFG_W0_FC_EN BIT(2)
#define PPE_AC_UNICAST_QUEUE_CFG_W0_CLR_AWARE BIT(3)
#define PPE_AC_UNICAST_QUEUE_CFG_W0_GRP_ID GENMASK(5, 4)
#define PPE_AC_UNICAST_QUEUE_CFG_W0_PRE_LIMIT GENMASK(16, 6)
#define PPE_AC_UNICAST_QUEUE_CFG_W0_DYNAMIC BIT(17)
#define PPE_AC_UNICAST_QUEUE_CFG_W0_WEIGHT GENMASK(20, 18)
#define PPE_AC_UNICAST_QUEUE_CFG_W0_THRESHOLD GENMASK(31, 21)
#define PPE_AC_UNICAST_QUEUE_CFG_W3_GRN_RESUME GENMASK(23, 13)
#define PPE_AC_UNICAST_QUEUE_SET_EN(tbl_cfg, value) \
FIELD_MODIFY(PPE_AC_UNICAST_QUEUE_CFG_W0_EN, tbl_cfg, value)
#define PPE_AC_UNICAST_QUEUE_SET_GRP_ID(tbl_cfg, value) \
FIELD_MODIFY(PPE_AC_UNICAST_QUEUE_CFG_W0_GRP_ID, tbl_cfg, value)
#define PPE_AC_UNICAST_QUEUE_SET_PRE_LIMIT(tbl_cfg, value) \
FIELD_MODIFY(PPE_AC_UNICAST_QUEUE_CFG_W0_PRE_LIMIT, tbl_cfg, value)
#define PPE_AC_UNICAST_QUEUE_SET_DYNAMIC(tbl_cfg, value) \
FIELD_MODIFY(PPE_AC_UNICAST_QUEUE_CFG_W0_DYNAMIC, tbl_cfg, value)
#define PPE_AC_UNICAST_QUEUE_SET_WEIGHT(tbl_cfg, value) \
FIELD_MODIFY(PPE_AC_UNICAST_QUEUE_CFG_W0_WEIGHT, tbl_cfg, value)
#define PPE_AC_UNICAST_QUEUE_SET_THRESHOLD(tbl_cfg, value) \
FIELD_MODIFY(PPE_AC_UNICAST_QUEUE_CFG_W0_THRESHOLD, tbl_cfg, value)
#define PPE_AC_UNICAST_QUEUE_SET_GRN_RESUME(tbl_cfg, value) \
FIELD_MODIFY(PPE_AC_UNICAST_QUEUE_CFG_W3_GRN_RESUME, (tbl_cfg) + 0x3, value)
/* PPE multicast queue (256-299) configurations. */
#define PPE_AC_MULTICAST_QUEUE_CFG_TBL_ADDR 0x84a000
#define PPE_AC_MULTICAST_QUEUE_CFG_TBL_ENTRIES 44
#define PPE_AC_MULTICAST_QUEUE_CFG_TBL_INC 0x10
#define PPE_AC_MULTICAST_QUEUE_CFG_W0_EN BIT(0)
#define PPE_AC_MULTICAST_QUEUE_CFG_W0_FC_EN BIT(1)
#define PPE_AC_MULTICAST_QUEUE_CFG_W0_CLR_AWARE BIT(2)
#define PPE_AC_MULTICAST_QUEUE_CFG_W0_GRP_ID GENMASK(4, 3)
#define PPE_AC_MULTICAST_QUEUE_CFG_W0_PRE_LIMIT GENMASK(15, 5)
#define PPE_AC_MULTICAST_QUEUE_CFG_W0_THRESHOLD GENMASK(26, 16)
#define PPE_AC_MULTICAST_QUEUE_CFG_W2_RESUME GENMASK(17, 7)
#define PPE_AC_MULTICAST_QUEUE_SET_EN(tbl_cfg, value) \
FIELD_MODIFY(PPE_AC_MULTICAST_QUEUE_CFG_W0_EN, tbl_cfg, value)
#define PPE_AC_MULTICAST_QUEUE_SET_GRN_GRP_ID(tbl_cfg, value) \
FIELD_MODIFY(PPE_AC_MULTICAST_QUEUE_CFG_W0_GRP_ID, tbl_cfg, value)
#define PPE_AC_MULTICAST_QUEUE_SET_GRN_PRE_LIMIT(tbl_cfg, value) \
FIELD_MODIFY(PPE_AC_MULTICAST_QUEUE_CFG_W0_PRE_LIMIT, tbl_cfg, value)
#define PPE_AC_MULTICAST_QUEUE_SET_GRN_THRESHOLD(tbl_cfg, value) \
FIELD_MODIFY(PPE_AC_MULTICAST_QUEUE_CFG_W0_THRESHOLD, tbl_cfg, value)
#define PPE_AC_MULTICAST_QUEUE_SET_GRN_RESUME(tbl_cfg, value) \
FIELD_MODIFY(PPE_AC_MULTICAST_QUEUE_CFG_W2_RESUME, (tbl_cfg) + 0x2, value)
/* PPE admission control group (0-3) configurations */
#define PPE_AC_GRP_CFG_TBL_ADDR 0x84c000
#define PPE_AC_GRP_CFG_TBL_ENTRIES 0x4
#define PPE_AC_GRP_CFG_TBL_INC 0x10
#define PPE_AC_GRP_W0_AC_EN BIT(0)
#define PPE_AC_GRP_W0_AC_FC_EN BIT(1)
#define PPE_AC_GRP_W0_CLR_AWARE BIT(2)
#define PPE_AC_GRP_W0_THRESHOLD_LOW GENMASK(31, 25)
#define PPE_AC_GRP_W1_THRESHOLD_HIGH GENMASK(3, 0)
#define PPE_AC_GRP_W1_BUF_LIMIT GENMASK(14, 4)
#define PPE_AC_GRP_W2_RESUME_GRN GENMASK(15, 5)
#define PPE_AC_GRP_W2_PRE_ALLOC GENMASK(26, 16)
#define PPE_AC_GRP_SET_BUF_LIMIT(tbl_cfg, value) \
FIELD_MODIFY(PPE_AC_GRP_W1_BUF_LIMIT, (tbl_cfg) + 0x1, value)
/* Counters for packets handled by unicast queues (0-255). */
#define PPE_AC_UNICAST_QUEUE_CNT_TBL_ADDR 0x84e000
#define PPE_AC_UNICAST_QUEUE_CNT_TBL_ENTRIES 256
#define PPE_AC_UNICAST_QUEUE_CNT_TBL_INC 0x10
#define PPE_AC_UNICAST_QUEUE_CNT_TBL_PEND_CNT GENMASK(12, 0)
/* Counters for packets handled by multicast queues (256-299). */
#define PPE_AC_MULTICAST_QUEUE_CNT_TBL_ADDR 0x852000
#define PPE_AC_MULTICAST_QUEUE_CNT_TBL_ENTRIES 44
#define PPE_AC_MULTICAST_QUEUE_CNT_TBL_INC 0x10
#define PPE_AC_MULTICAST_QUEUE_CNT_TBL_PEND_CNT GENMASK(12, 0)
/* Table addresses for per-queue enqueue setting. */
#define PPE_ENQ_OPR_TBL_ADDR 0x85c000
#define PPE_ENQ_OPR_TBL_ENTRIES 300
#define PPE_ENQ_OPR_TBL_INC 0x10
#define PPE_ENQ_OPR_TBL_ENQ_DISABLE BIT(0)
/* Unicast drop count includes the possible drops with WRED for the green,
* yellow and red categories.
*/
#define PPE_UNICAST_DROP_CNT_TBL_ADDR 0x9e0000
#define PPE_UNICAST_DROP_CNT_TBL_ENTRIES 1536
#define PPE_UNICAST_DROP_CNT_TBL_INC 0x10
#define PPE_UNICAST_DROP_TYPES 6
#define PPE_UNICAST_DROP_FORCE_OFFSET 3
/* There are 16 multicast queues dedicated to CPU port 0. Multicast drop
* count includes the force drop for green, yellow and red category packets.
*/
#define PPE_P0_MULTICAST_DROP_CNT_TBL_ADDR 0x9f0000
#define PPE_P0_MULTICAST_DROP_CNT_TBL_ENTRIES 48
#define PPE_P0_MULTICAST_DROP_CNT_TBL_INC 0x10
#define PPE_P0_MULTICAST_QUEUE_NUM 16
/* Each PPE physical port has four dedicated multicast queues, providing
* a total of 12 entries per port. The multicast drop count includes forced
* drops for green, yellow, and red category packets.
*/
#define PPE_MULTICAST_QUEUE_PORT_ADDR_INC 0x1000
#define PPE_MULTICAST_DROP_CNT_TBL_INC 0x10
#define PPE_MULTICAST_DROP_TYPES 3
#define PPE_MULTICAST_QUEUE_NUM 4
#define PPE_MULTICAST_DROP_CNT_TBL_ENTRIES 12
#define PPE_CPU_PORT_MULTICAST_FORCE_DROP_CNT_TBL_ADDR(mq_offset) \
(PPE_P0_MULTICAST_DROP_CNT_TBL_ADDR + \
(mq_offset) * PPE_P0_MULTICAST_DROP_CNT_TBL_INC * \
PPE_MULTICAST_DROP_TYPES)
#define PPE_P1_MULTICAST_DROP_CNT_TBL_ADDR \
(PPE_P0_MULTICAST_DROP_CNT_TBL_ADDR + PPE_MULTICAST_QUEUE_PORT_ADDR_INC)
#endif