mirror of
https://github.com/openwrt/openwrt.git
synced 2026-10-21 22:04:43 +04:00
qualcommax: qca_ppe: add tc-flower and ethtool n-tuple ACL offload
The ACL engine has 512 entries, and the driver uses two at fixed indices with no way to install a rule from userspace. Add an allocator that places a rule on the entry chains the hardware can merge, with range compares on even entries, move the two small-packet rules onto it, and implement cls_flower_add and cls_flower_del for MAC, IPv4, IPv6, L4 port and port range, ICMP, IP protocol, DSCP, TCP flag and fragment keys, refusing any other key. The actions are pass, drop, trap, skbedit priority, redirect, mirred mirror, which claims both of the port mirror's analyzers, pedit of the DSCP byte and police on one of the 512 ACL meters, and set_rxnfc gives ethtool -N the queue action, refusing queues 12 to 143, the CPU port queues the scheduler does not serve, and a VF or RSS context, which the switch does not have. The engine matches the highest PRI, so a rule's priority is the 9-bit span minus its tc preference. The address family comes from the control key, since cls_flower registers both address keys over one union, and from the registered address key where ethtool_rx_flow_rule_create() leaves the control key out. On IPQ8074 every accepted action installs in_hw, an ICMP drop filter drops in the switch, and a pedit to 0x88 moves the datagrams to another egress queue. Assisted-by: Claude:claude-opus-5-5 Signed-off-by: Julius Bairaktaris <julius@bairaktaris.de> Link: https://github.com/openwrt/openwrt/pull/25700 Signed-off-by: Robert Marko <robimarko@gmail.com>
This commit is contained in:
1 parent
7d15db3266
commit
9536cc0945
6 files changed
+1442
-20
No files matched your search
@@ -271,39 +271,95 @@
|
||||
#define PPE_RSS_HASH_MIX_IPV4(i) (0x0b0000 + 0x4390 + (i) * 0x4)
|
||||
#define PPE_RSS_HASH_FIN_IPV4(i) (0x0b0000 + 0x43b0 + (i) * 0x4)
|
||||
|
||||
/* --- ACL (rules in the IPO block, actions beside the L2 tables) ---
|
||||
* A rule, its mask and its action share one flat index. A rule whose RANGE_EN
|
||||
* is set must sit at an even index. There is no valid bit and no global
|
||||
* enable: a rule with an empty source bitmap matches nothing, one with ports
|
||||
* in it is live.
|
||||
/* --- ACL: rules and masks in the IPO block, actions beside the L2 tables,
|
||||
* hit counters in the ingress policer ---
|
||||
* A rule, its mask and its action share one flat index. The 512 indices are
|
||||
* 64 hardware lists of eight: a rule whose key is wider than one entry takes
|
||||
* several entries of one list and the list's RULE_EXT bits merge them into a
|
||||
* single match. A rule whose RANGE_EN is set compares one of its fields
|
||||
* against a range - that field's mask slot carries the maximum, the rest of
|
||||
* the mask stays a mask - and must sit at an even index. There is no valid
|
||||
* bit and no global enable: a rule with an empty source bitmap matches
|
||||
* nothing, one with ports in it is live.
|
||||
*/
|
||||
#define PPE_ACL_LISTS 64
|
||||
#define PPE_ACL_LIST_ENTRIES 8
|
||||
|
||||
#define PPE_ACL_RULE(i) (0x0b0000 + (i) * 0x10)
|
||||
/* 3 implemented words in a 4-word slot; whole slots are written so the
|
||||
* latch on the slot's last word always fires (same for the mask below).
|
||||
* Words 0 and 1 carry a 53-bit key whose fields belong to the rule type.
|
||||
*/
|
||||
#define PPE_ACL_RULE_WORDS 4
|
||||
#define PPE_ACL_L3_LEN GENMASK(15, 0) /* word 0; range min */
|
||||
#define PPE_ACL_IS_IPV6 BIT(17) /* word 1 */
|
||||
#define PPE_ACL_RANGE_EN BIT(21) /* word 1 */
|
||||
#define PPE_ACL_RULE_TYPE GENMASK(26, 23) /* word 1 */
|
||||
#define PPE_ACL_MAC_HI GENMASK(15, 0) /* w1: bytes 1-0 */
|
||||
#define PPE_ACL_IP_PORT GENMASK(15, 0) /* w0: L4 or ICMP */
|
||||
#define PPE_ACL_IP_LO GENMASK(31, 16) /* w0 */
|
||||
#define PPE_ACL_IP_HI GENMASK(15, 0) /* w1 */
|
||||
#define PPE_ACL_L3_LEN GENMASK(15, 0) /* w0; range min */
|
||||
#define PPE_ACL_L3_PROT GENMASK(23, 16) /* w0 */
|
||||
#define PPE_ACL_L3_DSCP GENMASK(31, 24) /* w0 */
|
||||
#define PPE_ACL_TCP_FLAGS GENMASK(6, 1) /* w1 */
|
||||
#define PPE_ACL_L3_FRAG BIT(16) /* w1 */
|
||||
#define PPE_ACL_IS_IPV6 BIT(17) /* w1 */
|
||||
#define PPE_ACL_RANGE_EN BIT(21) /* w1 */
|
||||
#define PPE_ACL_RULE_TYPE GENMASK(26, 23) /* w1 */
|
||||
#define PPE_ACL_TYPE_MAC_DA 0
|
||||
#define PPE_ACL_TYPE_MAC_SA 1
|
||||
#define PPE_ACL_TYPE_IPV4_DIP 4
|
||||
#define PPE_ACL_TYPE_IPV4_SIP 5
|
||||
#define PPE_ACL_TYPE_IPV6_DIP0 6 /* +1, +2 for the rest */
|
||||
#define PPE_ACL_TYPE_IPV6_SIP0 9
|
||||
#define PPE_ACL_TYPE_IPMISC 12
|
||||
#define PPE_ACL_SRC_LO GENMASK(31, 29) /* word 1: ports 0-2 */
|
||||
#define PPE_ACL_SRC_HI GENMASK(4, 0) /* word 2: ports 3-7 */
|
||||
#define PPE_ACL_SRC_TYPE GENMASK(28, 27) /* w1 */
|
||||
#define PPE_ACL_SRC_PORT_BMP 0
|
||||
#define PPE_ACL_SRC_LO GENMASK(31, 29) /* w1: ports 0-2 */
|
||||
#define PPE_ACL_SRC_HI GENMASK(4, 0) /* w2: ports 3-7 */
|
||||
#define PPE_ACL_RULE_PRI GENMASK(13, 5) /* w2 */
|
||||
#define PPE_ACL_MASK(i) (0x0b2000 + (i) * 0x10)
|
||||
#define PPE_ACL_MASK_WORDS 4 /* 2 implemented; same field layout
|
||||
* as the rule, and under RANGE_EN
|
||||
* the length field carries the
|
||||
* range max
|
||||
* the ranged field's slot carries
|
||||
* its maximum
|
||||
*/
|
||||
/* One register per hardware list, one bit per mergeable pair of its entries:
|
||||
* EXT1 merges (0,1) (2,3) (4,5) (6,7), EXT2 merges (0,2) (4,6), EXT4 (0,4).
|
||||
* No other pairing exists, which is what limits a wide rule's placement.
|
||||
*/
|
||||
#define PPE_ACL_RULE_EXT1(l) (0x0b4000 + (l) * 0x4)
|
||||
#define PPE_ACL_RULE_EXT2(l) (0x0b4100 + (l) * 0x4)
|
||||
#define PPE_ACL_RULE_EXT4(l) (0x0b4200 + (l) * 0x4)
|
||||
#define PPE_ACL_ACTION(i) (0x068000 + (i) * 0x20)
|
||||
/* 5 implemented words in an 8-word slot; the entry latches on the write to
|
||||
* the slot's last word, so all 8 are written.
|
||||
*/
|
||||
#define PPE_ACL_ACTION_WORDS 8
|
||||
#define PPE_ACL_DEST_CHANGE_EN BIT(0) /* word 0 */
|
||||
#define PPE_ACL_FWD_CMD GENMASK(2, 1) /* word 0 */
|
||||
#define PPE_ACL_FWD_FORWARD 0
|
||||
#define PPE_ACL_FWD_DROP 1
|
||||
#define PPE_ACL_FWD_RDT_CPU 3
|
||||
/* The destination that replaces the one the lookup found: a twelve-bit
|
||||
* value under a two-bit type.
|
||||
*/
|
||||
#define PPE_ACL_DEST_VALUE GENMASK(14, 3) /* word 0 */
|
||||
#define PPE_ACL_DEST_TYPE GENMASK(16, 15) /* word 0 */
|
||||
#define PPE_ACL_DEST_PORT_BMP 3
|
||||
#define PPE_ACL_MIRROR_EN BIT(17) /* word 0 */
|
||||
#define PPE_ACL_DSCP_TC_CHANGE_EN BIT(14) /* word 2 */
|
||||
#define PPE_ACL_DSCP_TC GENMASK(22, 15) /* word 2 */
|
||||
#define PPE_ACL_PRI_CHANGE_EN BIT(3) /* word 3 */
|
||||
#define PPE_ACL_PRI GENMASK(7, 4) /* word 3 */
|
||||
#define PPE_ACL_POLICER_EN BIT(11) /* word 3 */
|
||||
#define PPE_ACL_POLICER_INDEX GENMASK(20, 12) /* word 3 */
|
||||
#define PPE_ACL_QID_EN BIT(21) /* word 3 */
|
||||
#define PPE_ACL_QID GENMASK(29, 22) /* word 3 */
|
||||
/* The counters live in the ingress policer block, not the IPO: the vendor
|
||||
* reaches them at its 0x100000 base plus the table's own 0x74000. Packets in
|
||||
* word 0, the low 32 bits of the byte count in word 1, its top 8 in word 2.
|
||||
*/
|
||||
#define PPE_ACL_CNT(i) (0x174000 + (i) * 0x10)
|
||||
#define PPE_ACL_CNT_ENTRIES 512
|
||||
#define PPE_ACL_CNT_WORDS 3
|
||||
/* Read-only, and counting whether or not any rule is installed. */
|
||||
#define PPE_ACL_GLB_HIT_CNT (0x0b0000 + 0x430c)
|
||||
#define PPE_ACL_GLB_MISS_CNT (0x0b0000 + 0x4310)
|
||||
@@ -466,6 +522,29 @@
|
||||
|
||||
#define PPE_POLICER_TIME_SLOT (PPE_POLICER_BASE + 0x40)
|
||||
#define PPE_POLICER_SLOT_TIME GENMASK(9, 0)
|
||||
/* The refresh period every meter in the block shares, in units of 8 PPE
|
||||
* clocks, as ppe_rate_limit_init programs it.
|
||||
*/
|
||||
#define PPE_POLICER_SLOT 600
|
||||
|
||||
/* One meter per classifier rule, bound by the rule's action. The fields are
|
||||
* the port meter's in a different order and without its frame-type filter,
|
||||
* and the two words past the rate carry the exceed and violate actions: left
|
||||
* at zero, a violation drops.
|
||||
*/
|
||||
#define PPE_ACL_METER(i) (PPE_POLICER_BASE + 0x4000 + (i) * 0x10)
|
||||
#define PPE_ACL_METER_ENTRIES 512
|
||||
#define PPE_ACL_METER_EN BIT(0) /* word 0 */
|
||||
#define PPE_ACL_METER_MODE BIT(3) /* word 0 */
|
||||
#define PPE_ACL_METER_TOKEN_UNIT GENMASK(6, 4) /* word 0 */
|
||||
#define PPE_ACL_METER_CBS GENMASK(23, 8) /* word 0 */
|
||||
#define PPE_ACL_METER_CIR_LO GENMASK(31, 24) /* word 0 */
|
||||
#define PPE_ACL_METER_CIR_HI GENMASK(9, 0) /* word 1 */
|
||||
|
||||
/* The meter's token buckets, committed and excess, two words that commit on
|
||||
* the second - the port meter's table one block over, per meter index.
|
||||
*/
|
||||
#define PPE_ACL_METER_CRDT(i) (PPE_POLICER_BASE + 0x8000 + (i) * 0x10)
|
||||
|
||||
#define PPE_PORT_METER_W0(p) (PPE_POLICER_BASE + 0xc000 + (p) * 0x10)
|
||||
#define PPE_METER_EN BIT(0)
|
||||
@@ -701,6 +780,10 @@
|
||||
#define PPE_MAX_SP_PRI 8
|
||||
#define PPE_L0_QUEUES 300
|
||||
#define PPE_L0_UCAST_QUEUES 256
|
||||
/* The CPU port's unicast queues the L0 scheduler serves (l0_port0[]). */
|
||||
#define PPE_CPU_UCAST_QUEUES 12
|
||||
/* First unicast queue of a user port. */
|
||||
#define PPE_PORT_UCAST_BASE 144
|
||||
|
||||
#define PPE_BM_BUF_SIZE 256
|
||||
#define PPE_BM_PORTS 15
|
||||
@@ -825,6 +908,14 @@ struct qca_ppe_priv {
|
||||
* holds none.
|
||||
*/
|
||||
struct mutex vlan_lock;
|
||||
/* Free entries of every ACL hardware list. Guarded by its own lock
|
||||
* because the small-packet module parameters reach the table from a
|
||||
* writer that holds no rtnl.
|
||||
*/
|
||||
u8 acl_free[PPE_ACL_LISTS];
|
||||
DECLARE_BITMAP(acl_meter_used, PPE_ACL_METER_ENTRIES);
|
||||
struct list_head acl_rules;
|
||||
struct mutex acl_lock;
|
||||
/* Indexed by direction: egress 0, ingress 1. */
|
||||
u8 mirror_port[2];
|
||||
u16 mirror_ref[2];
|
||||
@@ -907,6 +998,7 @@ struct tc_ets_qopt_offload;
|
||||
struct tc_prio_qopt_offload;
|
||||
struct tc_query_caps_base;
|
||||
struct tc_mqprio_qopt_offload;
|
||||
struct flow_cls_offload;
|
||||
|
||||
void ppe_scheduler_init(struct qca_ppe_priv *priv);
|
||||
int qca_ppe_setup_tc(struct dsa_switch *ds, int port, enum tc_setup_type type,
|
||||
@@ -938,6 +1030,8 @@ int qca_ppe_port_policer_add(struct dsa_switch *ds, int port,
|
||||
const struct flow_action_police *policer,
|
||||
struct netlink_ext_ack *extack);
|
||||
void qca_ppe_port_policer_del(struct dsa_switch *ds, int port);
|
||||
int ppe_token_bucket(unsigned long clk, u32 slot, u64 rate_bps, u32 burst,
|
||||
u32 cir_max, u32 cbs_max, u32 *cir, u32 *cbs);
|
||||
|
||||
int ppe_vsi_alloc(struct qca_ppe_priv *priv);
|
||||
void ppe_vsi_free(struct qca_ppe_priv *priv, u32 vsi);
|
||||
@@ -959,4 +1053,17 @@ unsigned long ppe_clk_rate(struct qca_ppe_priv *priv);
|
||||
void ppe_debugfs_init(struct qca_ppe_priv *priv);
|
||||
void ppe_debugfs_exit(struct qca_ppe_priv *priv);
|
||||
|
||||
void ppe_acl_init(struct qca_ppe_priv *priv);
|
||||
void ppe_acl_exit(struct qca_ppe_priv *priv);
|
||||
int qca_ppe_cls_flower_add(struct dsa_switch *ds, int port,
|
||||
struct flow_cls_offload *cls, bool ingress);
|
||||
int qca_ppe_cls_flower_del(struct dsa_switch *ds, int port,
|
||||
struct flow_cls_offload *cls, bool ingress);
|
||||
int qca_ppe_set_rxnfc(struct dsa_switch *ds, int port,
|
||||
struct ethtool_rxnfc *nfc);
|
||||
int qca_ppe_get_rxnfc(struct dsa_switch *ds, int port,
|
||||
struct ethtool_rxnfc *nfc, u32 *rule_locs);
|
||||
int ppe_mirror_analyzer_get(struct qca_ppe_priv *priv, int to_port);
|
||||
void ppe_mirror_analyzer_put(struct qca_ppe_priv *priv);
|
||||
|
||||
#endif
|
||||
File diff suppressed because it is too large.
Load diff
@@ -1952,6 +1952,19 @@ static void ppe_mirror_put(struct qca_ppe_priv *priv, u8 dirs)
|
||||
ppe_mirror_analyzer_write(priv);
|
||||
}
|
||||
|
||||
/* Which analyzer a classifier rule's mirror uses is not known, so it claims
|
||||
* both.
|
||||
*/
|
||||
int ppe_mirror_analyzer_get(struct qca_ppe_priv *priv, int to_port)
|
||||
{
|
||||
return ppe_mirror_get(priv, to_port, BIT(0) | BIT(1));
|
||||
}
|
||||
|
||||
void ppe_mirror_analyzer_put(struct qca_ppe_priv *priv)
|
||||
{
|
||||
ppe_mirror_put(priv, BIT(0) | BIT(1));
|
||||
}
|
||||
|
||||
int qca_ppe_port_mirror_add(struct dsa_switch *ds, int port,
|
||||
struct dsa_mall_mirror_tc_entry *mirror,
|
||||
bool ingress, struct netlink_ext_ack *extack)
|
||||
@@ -1995,6 +2008,10 @@ void qca_ppe_port_mirror_del(struct dsa_switch *ds, int port,
|
||||
|
||||
static const struct dsa_switch_ops qca_ppe_ops = {
|
||||
.port_setup_tc = qca_ppe_setup_tc,
|
||||
.cls_flower_add = qca_ppe_cls_flower_add,
|
||||
.cls_flower_del = qca_ppe_cls_flower_del,
|
||||
.get_rxnfc = qca_ppe_get_rxnfc,
|
||||
.set_rxnfc = qca_ppe_set_rxnfc,
|
||||
.port_mirror_add = qca_ppe_port_mirror_add,
|
||||
.port_mirror_del = qca_ppe_port_mirror_del,
|
||||
.port_policer_add = qca_ppe_port_policer_add,
|
||||
@@ -2250,19 +2267,24 @@ static int qca_ppe_probe(struct platform_device *pdev)
|
||||
|
||||
ppe_mac_hw_init(priv);
|
||||
ppe_ctrlpkt_init(priv);
|
||||
ppe_acl_init(priv);
|
||||
|
||||
if (data->type == PPE_TYPE_IPQ6018)
|
||||
ppe_ipq6018_mux_setup(priv);
|
||||
|
||||
ret = dsa_register_switch(ds);
|
||||
if (ret)
|
||||
return ret;
|
||||
goto err_acl;
|
||||
|
||||
ppe_debugfs_init(priv);
|
||||
|
||||
platform_set_drvdata(pdev, priv);
|
||||
|
||||
return 0;
|
||||
|
||||
err_acl:
|
||||
ppe_acl_exit(priv);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void qca_ppe_remove(struct platform_device *pdev)
|
||||
@@ -2271,6 +2293,7 @@ static void qca_ppe_remove(struct platform_device *pdev)
|
||||
|
||||
ppe_debugfs_exit(priv);
|
||||
dsa_unregister_switch(&priv->ds);
|
||||
ppe_acl_exit(priv);
|
||||
}
|
||||
|
||||
static const struct ppe_data ipq6018_ppe_data = {
|
||||
|
||||
@@ -1066,7 +1066,6 @@ static void ppe_rss_hash_init(struct qca_ppe_priv *priv)
|
||||
* the one that gets programmed, exactly as qca-ssdk picks it.
|
||||
*/
|
||||
#define PPE_SHAPER_SLOT 8
|
||||
#define PPE_POLICER_SLOT 600
|
||||
#define PPE_TOKEN_UNIT_MAX 16384
|
||||
#define PPE_BUCKET_UNIT 65536
|
||||
/* 12 byte inter-packet gap plus the 8 byte preamble and start delimiter: what
|
||||
@@ -1083,9 +1082,8 @@ unsigned long ppe_clk_rate(struct qca_ppe_priv *priv)
|
||||
return clk_get_rate(priv->ppe_clk);
|
||||
}
|
||||
|
||||
static int ppe_token_bucket(unsigned long clk, u32 slot, u64 rate_bps,
|
||||
u32 burst, u32 cir_max, u32 cbs_max,
|
||||
u32 *cir, u32 *cbs)
|
||||
int ppe_token_bucket(unsigned long clk, u32 slot, u64 rate_bps, u32 burst,
|
||||
u32 cir_max, u32 cbs_max, u32 *cir, u32 *cbs)
|
||||
{
|
||||
int sel;
|
||||
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
obj-$(CONFIG_QCA7000_UART) += qcauart.o
|
||||
qcauart-objs := qca_uart.o
|
||||
+obj-$(CONFIG_QCOM_80211AX_PPE) += qca_ppe.o
|
||||
+qca_ppe-objs := qca_ppe_main.o qca_ppe_vlan.o qca_ppe_scheduler.o qca_ppe_debugfs.o
|
||||
+qca_ppe-objs := qca_ppe_main.o qca_ppe_vlan.o qca_ppe_scheduler.o qca_ppe_debugfs.o qca_ppe_acl.o
|
||||
|
||||
obj-y += emac/
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
@@ -10,6 +10,7 @@ obj-$(CONFIG_QCA7000_UART) += qcauart.o
|
||||
qcauart-objs := qca_uart.o
|
||||
obj-$(CONFIG_QCOM_80211AX_PPE) += qca_ppe.o
|
||||
qca_ppe-objs := qca_ppe_main.o qca_ppe_vlan.o qca_ppe_scheduler.o qca_ppe_debugfs.o
|
||||
qca_ppe-objs := qca_ppe_main.o qca_ppe_vlan.o qca_ppe_scheduler.o qca_ppe_debugfs.o qca_ppe_acl.o
|
||||
+obj-$(CONFIG_QCOM_EDMA) += qca_edma.o
|
||||
|
||||
obj-y += emac/
|
||||
|
||||
Reference in new issue
Block a user