From b994fa991065b7a5535bd85e311bc4cd33096d22 Mon Sep 17 00:00:00 2001 From: Markus Stockhausen Date: Sun, 13 Sep 2026 14:01:17 +0200 Subject: [PATCH] realtek: dsa: move PIE handling to separate module The SoC-specific driver files still contain the complete Packet Inspection Engine implementations. This makes the files difficult to navigate and mixes PIE handling with unrelated hardware functionality. Move the common PIE interface and the SoC-specific implementations into new pie.c and pie.h files. Keep the existing per-SoC operations and their assignment in the switch configuration unchanged. Packet counters remain in the SoC-specific files because they are also used by the L3 offload implementation. This is a code reorganization and does not change functionality. Assisted-by: ChatGPT (OpenAI GPT-5.6 Sol) Link: https://github.com/openwrt/openwrt/pull/25160 Signed-off-by: Markus Stockhausen --- .../drivers/net/dsa/rtl83xx/Makefile | 2 +- .../files-6.18/drivers/net/dsa/rtl83xx/pie.c | 3069 +++++++++++++++++ .../files-6.18/drivers/net/dsa/rtl83xx/pie.h | 40 + .../drivers/net/dsa/rtl83xx/rtl-otto.h | 2 - .../drivers/net/dsa/rtl83xx/rtl838x.c | 963 +----- .../drivers/net/dsa/rtl83xx/rtl839x.c | 818 +---- .../drivers/net/dsa/rtl83xx/rtl930x.c | 627 +--- .../drivers/net/dsa/rtl83xx/rtl931x.c | 649 +--- 8 files changed, 3114 insertions(+), 3056 deletions(-) create mode 100644 target/linux/realtek/files-6.18/drivers/net/dsa/rtl83xx/pie.c create mode 100644 target/linux/realtek/files-6.18/drivers/net/dsa/rtl83xx/pie.h diff --git a/target/linux/realtek/files-6.18/drivers/net/dsa/rtl83xx/Makefile b/target/linux/realtek/files-6.18/drivers/net/dsa/rtl83xx/Makefile index 3144f330903..b9e0662bf78 100644 --- a/target/linux/realtek/files-6.18/drivers/net/dsa/rtl83xx/Makefile +++ b/target/linux/realtek/files-6.18/drivers/net/dsa/rtl83xx/Makefile @@ -1,3 +1,3 @@ # SPDX-License-Identifier: GPL-2.0 obj-$(CONFIG_NET_DSA_RTL83XX) += rtl_otto_dsa.o -rtl_otto_dsa-objs := common.o dsa.o rtl838x.o rtl839x.o rtl930x.o rtl931x.o debugfs.o qos.o tc.o vlan.o l3.o +rtl_otto_dsa-objs := common.o dsa.o rtl838x.o rtl839x.o rtl930x.o rtl931x.o debugfs.o qos.o tc.o pie.o vlan.o l3.o diff --git a/target/linux/realtek/files-6.18/drivers/net/dsa/rtl83xx/pie.c b/target/linux/realtek/files-6.18/drivers/net/dsa/rtl83xx/pie.c new file mode 100644 index 00000000000..9e4f93cc235 --- /dev/null +++ b/target/linux/realtek/files-6.18/drivers/net/dsa/rtl83xx/pie.c @@ -0,0 +1,3069 @@ +// SPDX-License-Identifier: GPL-2.0-only + +#include +#include +#include + +#include "pie.h" +#include "rtl-otto.h" + +/* RTL838X */ + +/* see_dal_maple_acl_log2PhyTmplteField and src/app/diag_v2/src/diag_acl.c */ +/* Definition of the RTL838X-specific template field IDs as used in the PIE */ +enum rtl838x_template_field_id { + RTL838X_TEMPLATE_FIELD_SPMMASK = 0, + RTL838X_TEMPLATE_FIELD_SPM0 = 1, /* Source portmask ports 0-15 */ + RTL838X_TEMPLATE_FIELD_SPM1 = 2, /* Source portmask ports 16-28 */ + RTL838X_TEMPLATE_FIELD_RANGE_CHK = 3, + RTL838X_TEMPLATE_FIELD_DMAC0 = 4, /* Destination MAC [15:0] */ + RTL838X_TEMPLATE_FIELD_DMAC1 = 5, /* Destination MAC [31:16] */ + RTL838X_TEMPLATE_FIELD_DMAC2 = 6, /* Destination MAC [47:32] */ + RTL838X_TEMPLATE_FIELD_SMAC0 = 7, /* Source MAC [15:0] */ + RTL838X_TEMPLATE_FIELD_SMAC1 = 8, /* Source MAC [31:16] */ + RTL838X_TEMPLATE_FIELD_SMAC2 = 9, /* Source MAC [47:32] */ + RTL838X_TEMPLATE_FIELD_ETHERTYPE = 10, /* Ethernet typ */ + RTL838X_TEMPLATE_FIELD_OTAG = 11, /* Outer VLAN tag */ + RTL838X_TEMPLATE_FIELD_ITAG = 12, /* Inner VLAN tag */ + RTL838X_TEMPLATE_FIELD_SIP0 = 13, /* IPv4 or IPv6 source IP[15:0] or ARP/RARP */ + /* source protocol address in header */ + RTL838X_TEMPLATE_FIELD_SIP1 = 14, /* IPv4 or IPv6 source IP[31:16] or ARP/RARP */ + RTL838X_TEMPLATE_FIELD_DIP0 = 15, /* IPv4 or IPv6 destination IP[15:0] */ + RTL838X_TEMPLATE_FIELD_DIP1 = 16, /* IPv4 or IPv6 destination IP[31:16] */ + RTL838X_TEMPLATE_FIELD_IP_TOS_PROTO = 17, /* IPv4 TOS/IPv6 traffic class and */ + /* IPv4 proto/IPv6 next header fields */ + RTL838X_TEMPLATE_FIELD_L34_HEADER = 18, /* packet with extra tag and IPv6 with auth, dest, */ + /* frag, route, hop-by-hop option header, */ + /* IGMP type, TCP flag */ + RTL838X_TEMPLATE_FIELD_L4_SPORT = 19, /* TCP/UDP source port */ + RTL838X_TEMPLATE_FIELD_L4_DPORT = 20, /* TCP/UDP destination port */ + RTL838X_TEMPLATE_FIELD_ICMP_IGMP = 21, + RTL838X_TEMPLATE_FIELD_IP_RANGE = 22, + RTL838X_TEMPLATE_FIELD_FIELD_SELECTOR_VALID = 23, /* Field selector mask */ + RTL838X_TEMPLATE_FIELD_FIELD_SELECTOR_0 = 24, + RTL838X_TEMPLATE_FIELD_FIELD_SELECTOR_1 = 25, + RTL838X_TEMPLATE_FIELD_FIELD_SELECTOR_2 = 26, + RTL838X_TEMPLATE_FIELD_FIELD_SELECTOR_3 = 27, + RTL838X_TEMPLATE_FIELD_SIP2 = 28, /* IPv6 source IP[47:32] */ + RTL838X_TEMPLATE_FIELD_SIP3 = 29, /* IPv6 source IP[63:48] */ + RTL838X_TEMPLATE_FIELD_SIP4 = 30, /* IPv6 source IP[79:64] */ + RTL838X_TEMPLATE_FIELD_SIP5 = 31, /* IPv6 source IP[95:80] */ + RTL838X_TEMPLATE_FIELD_SIP6 = 32, /* IPv6 source IP[111:96] */ + RTL838X_TEMPLATE_FIELD_SIP7 = 33, /* IPv6 source IP[127:112] */ + RTL838X_TEMPLATE_FIELD_DIP2 = 34, /* IPv6 destination IP[47:32] */ + RTL838X_TEMPLATE_FIELD_DIP3 = 35, /* IPv6 destination IP[63:48] */ + RTL838X_TEMPLATE_FIELD_DIP4 = 36, /* IPv6 destination IP[79:64] */ + RTL838X_TEMPLATE_FIELD_DIP5 = 37, /* IPv6 destination IP[95:80] */ + RTL838X_TEMPLATE_FIELD_DIP6 = 38, /* IPv6 destination IP[111:96] */ + RTL838X_TEMPLATE_FIELD_DIP7 = 39, /* IPv6 destination IP[127:112] */ + RTL838X_TEMPLATE_FIELD_FWD_VID = 40, /* Forwarding VLAN-ID */ + RTL838X_TEMPLATE_FIELD_FLOW_LABEL = 41, +}; + +/* The RTL838X SoCs use 5 fixed templates with definitions for which data fields are to + * be copied from the Ethernet Frame header into the 12 User-definable fields of the Packet + * Inspection Engine's buffer. The following defines the field contents for each of the fixed + * templates. Additionally, 3 user-definable templates can be set up via the definitions + * in RTL838X_ACL_TMPLTE_CTRL control registers. + * TODO: See all src/app/diag_v2/src/diag_pie.c + */ +#define RTL838X_N_FIXED_TEMPLATES 5 +static enum rtl838x_template_field_id rtl838x_fixed_templates[RTL838X_N_FIXED_TEMPLATES][N_FIXED_FIELDS] = { + { + RTL838X_TEMPLATE_FIELD_SPM0, RTL838X_TEMPLATE_FIELD_SPM1, RTL838X_TEMPLATE_FIELD_OTAG, + RTL838X_TEMPLATE_FIELD_SMAC0, RTL838X_TEMPLATE_FIELD_SMAC1, RTL838X_TEMPLATE_FIELD_SMAC2, + RTL838X_TEMPLATE_FIELD_DMAC0, RTL838X_TEMPLATE_FIELD_DMAC1, RTL838X_TEMPLATE_FIELD_DMAC2, + RTL838X_TEMPLATE_FIELD_ETHERTYPE, RTL838X_TEMPLATE_FIELD_ITAG, RTL838X_TEMPLATE_FIELD_RANGE_CHK + }, { + RTL838X_TEMPLATE_FIELD_SIP0, RTL838X_TEMPLATE_FIELD_SIP1, RTL838X_TEMPLATE_FIELD_DIP0, + RTL838X_TEMPLATE_FIELD_DIP1, RTL838X_TEMPLATE_FIELD_IP_TOS_PROTO, RTL838X_TEMPLATE_FIELD_L4_SPORT, + RTL838X_TEMPLATE_FIELD_L4_DPORT, RTL838X_TEMPLATE_FIELD_ICMP_IGMP, RTL838X_TEMPLATE_FIELD_ITAG, + RTL838X_TEMPLATE_FIELD_RANGE_CHK, RTL838X_TEMPLATE_FIELD_SPM0, RTL838X_TEMPLATE_FIELD_SPM1 + }, { + RTL838X_TEMPLATE_FIELD_DMAC0, RTL838X_TEMPLATE_FIELD_DMAC1, RTL838X_TEMPLATE_FIELD_DMAC2, + RTL838X_TEMPLATE_FIELD_ITAG, RTL838X_TEMPLATE_FIELD_ETHERTYPE, RTL838X_TEMPLATE_FIELD_IP_TOS_PROTO, + RTL838X_TEMPLATE_FIELD_L4_DPORT, RTL838X_TEMPLATE_FIELD_L4_SPORT, RTL838X_TEMPLATE_FIELD_SIP0, + RTL838X_TEMPLATE_FIELD_SIP1, RTL838X_TEMPLATE_FIELD_DIP0, RTL838X_TEMPLATE_FIELD_DIP1 + }, { + RTL838X_TEMPLATE_FIELD_DIP0, RTL838X_TEMPLATE_FIELD_DIP1, RTL838X_TEMPLATE_FIELD_DIP2, + RTL838X_TEMPLATE_FIELD_DIP3, RTL838X_TEMPLATE_FIELD_DIP4, RTL838X_TEMPLATE_FIELD_DIP5, + RTL838X_TEMPLATE_FIELD_DIP6, RTL838X_TEMPLATE_FIELD_DIP7, RTL838X_TEMPLATE_FIELD_L4_DPORT, + RTL838X_TEMPLATE_FIELD_L4_SPORT, RTL838X_TEMPLATE_FIELD_ICMP_IGMP, RTL838X_TEMPLATE_FIELD_IP_TOS_PROTO + }, { + RTL838X_TEMPLATE_FIELD_SIP0, RTL838X_TEMPLATE_FIELD_SIP1, RTL838X_TEMPLATE_FIELD_SIP2, + RTL838X_TEMPLATE_FIELD_SIP3, RTL838X_TEMPLATE_FIELD_SIP4, RTL838X_TEMPLATE_FIELD_SIP5, + RTL838X_TEMPLATE_FIELD_SIP6, RTL838X_TEMPLATE_FIELD_SIP7, RTL838X_TEMPLATE_FIELD_ITAG, + RTL838X_TEMPLATE_FIELD_RANGE_CHK, RTL838X_TEMPLATE_FIELD_SPM0, RTL838X_TEMPLATE_FIELD_SPM1 + }, +}; + +static void rtl838x_pie_lookup_enable(struct rtl838x_switch_priv *priv, int index) +{ + int block = index / PIE_BLOCK_SIZE; + u32 block_state = sw_r32(RTL838X_ACL_BLK_LOOKUP_CTRL); + + /* Make sure rule-lookup is enabled in the block */ + if (!(block_state & BIT(block))) + sw_w32(block_state | BIT(block), RTL838X_ACL_BLK_LOOKUP_CTRL); +} + +static void rtl838x_pie_rule_del(struct rtl838x_switch_priv *priv, int index_from, int index_to) +{ + int block_from = index_from / PIE_BLOCK_SIZE; + int block_to = index_to / PIE_BLOCK_SIZE; + u32 v = (index_from << 1) | (index_to << 12) | BIT(0); + u32 block_state; + + pr_debug("%s: from %d to %d\n", __func__, index_from, index_to); + mutex_lock(&priv->reg_mutex); + + /* Remember currently active blocks */ + block_state = sw_r32(RTL838X_ACL_BLK_LOOKUP_CTRL); + + /* Make sure rule-lookup is disabled in the relevant blocks */ + for (int block = block_from; block <= block_to; block++) { + if (block_state & BIT(block)) + sw_w32(block_state & (~BIT(block)), RTL838X_ACL_BLK_LOOKUP_CTRL); + } + + /* Write from-to and execute bit into control register */ + sw_w32(v, RTL838X_ACL_CLR_CTRL); + + /* Wait until command has completed */ + do { + } while (sw_r32(RTL838X_ACL_CLR_CTRL) & BIT(0)); + + /* Re-enable rule lookup */ + for (int block = block_from; block <= block_to; block++) { + if (!(block_state & BIT(block))) + sw_w32(block_state | BIT(block), RTL838X_ACL_BLK_LOOKUP_CTRL); + } + + mutex_unlock(&priv->reg_mutex); +} + +/* Reads the intermediate representation of the templated match-fields of the + * PIE rule in the pie_rule structure and fills in the raw data fields in the + * raw register space r[]. + * The register space configuration size is identical for the RTL8380/90 and RTL9300, + * however the RTL9310 has 2 more registers / fields and the physical field-ids + * are specific to every platform. + */ +static void rtl838x_write_pie_templated(u32 r[], struct pie_rule *pr, enum rtl838x_template_field_id t[]) +{ + for (int i = 0; i < N_FIXED_FIELDS; i++) { + enum rtl838x_template_field_id field_type = t[i]; + u16 data = 0, data_m = 0; + + switch (field_type) { + case RTL838X_TEMPLATE_FIELD_SPM0: + data = pr->spm; + data_m = pr->spm_m; + break; + case RTL838X_TEMPLATE_FIELD_SPM1: + data = pr->spm >> 16; + data_m = pr->spm_m >> 16; + break; + case RTL838X_TEMPLATE_FIELD_OTAG: + data = pr->otag; + data_m = pr->otag_m; + break; + case RTL838X_TEMPLATE_FIELD_SMAC0: + data = pr->smac[4]; + data = (data << 8) | pr->smac[5]; + data_m = pr->smac_m[4]; + data_m = (data_m << 8) | pr->smac_m[5]; + break; + case RTL838X_TEMPLATE_FIELD_SMAC1: + data = pr->smac[2]; + data = (data << 8) | pr->smac[3]; + data_m = pr->smac_m[2]; + data_m = (data_m << 8) | pr->smac_m[3]; + break; + case RTL838X_TEMPLATE_FIELD_SMAC2: + data = pr->smac[0]; + data = (data << 8) | pr->smac[1]; + data_m = pr->smac_m[0]; + data_m = (data_m << 8) | pr->smac_m[1]; + break; + case RTL838X_TEMPLATE_FIELD_DMAC0: + data = pr->dmac[4]; + data = (data << 8) | pr->dmac[5]; + data_m = pr->dmac_m[4]; + data_m = (data_m << 8) | pr->dmac_m[5]; + break; + case RTL838X_TEMPLATE_FIELD_DMAC1: + data = pr->dmac[2]; + data = (data << 8) | pr->dmac[3]; + data_m = pr->dmac_m[2]; + data_m = (data_m << 8) | pr->dmac_m[3]; + break; + case RTL838X_TEMPLATE_FIELD_DMAC2: + data = pr->dmac[0]; + data = (data << 8) | pr->dmac[1]; + data_m = pr->dmac_m[0]; + data_m = (data_m << 8) | pr->dmac_m[1]; + break; + case RTL838X_TEMPLATE_FIELD_ETHERTYPE: + data = pr->ethertype; + data_m = pr->ethertype_m; + break; + case RTL838X_TEMPLATE_FIELD_ITAG: + data = pr->itag; + data_m = pr->itag_m; + break; + case RTL838X_TEMPLATE_FIELD_RANGE_CHK: + data = pr->field_range_check; + data_m = pr->field_range_check_m; + break; + case RTL838X_TEMPLATE_FIELD_SIP0: + if (pr->is_ipv6) { + data = pr->sip6.s6_addr16[7]; + data_m = pr->sip6_m.s6_addr16[7]; + } else { + data = pr->sip; + data_m = pr->sip_m; + } + break; + case RTL838X_TEMPLATE_FIELD_SIP1: + if (pr->is_ipv6) { + data = pr->sip6.s6_addr16[6]; + data_m = pr->sip6_m.s6_addr16[6]; + } else { + data = pr->sip >> 16; + data_m = pr->sip_m >> 16; + } + break; + case RTL838X_TEMPLATE_FIELD_SIP2: + case RTL838X_TEMPLATE_FIELD_SIP3: + case RTL838X_TEMPLATE_FIELD_SIP4: + case RTL838X_TEMPLATE_FIELD_SIP5: + case RTL838X_TEMPLATE_FIELD_SIP6: + case RTL838X_TEMPLATE_FIELD_SIP7: + data = pr->sip6.s6_addr16[5 - (field_type - RTL838X_TEMPLATE_FIELD_SIP2)]; + data_m = pr->sip6_m.s6_addr16[5 - (field_type - RTL838X_TEMPLATE_FIELD_SIP2)]; + break; + case RTL838X_TEMPLATE_FIELD_DIP0: + if (pr->is_ipv6) { + data = pr->dip6.s6_addr16[7]; + data_m = pr->dip6_m.s6_addr16[7]; + } else { + data = pr->dip; + data_m = pr->dip_m; + } + break; + case RTL838X_TEMPLATE_FIELD_DIP1: + if (pr->is_ipv6) { + data = pr->dip6.s6_addr16[6]; + data_m = pr->dip6_m.s6_addr16[6]; + } else { + data = pr->dip >> 16; + data_m = pr->dip_m >> 16; + } + break; + case RTL838X_TEMPLATE_FIELD_DIP2: + case RTL838X_TEMPLATE_FIELD_DIP3: + case RTL838X_TEMPLATE_FIELD_DIP4: + case RTL838X_TEMPLATE_FIELD_DIP5: + case RTL838X_TEMPLATE_FIELD_DIP6: + case RTL838X_TEMPLATE_FIELD_DIP7: + data = pr->dip6.s6_addr16[5 - (field_type - RTL838X_TEMPLATE_FIELD_DIP2)]; + data_m = pr->dip6_m.s6_addr16[5 - (field_type - RTL838X_TEMPLATE_FIELD_DIP2)]; + break; + case RTL838X_TEMPLATE_FIELD_IP_TOS_PROTO: + data = pr->tos_proto; + data_m = pr->tos_proto_m; + break; + case RTL838X_TEMPLATE_FIELD_L4_SPORT: + data = pr->sport; + data_m = pr->sport_m; + break; + case RTL838X_TEMPLATE_FIELD_L4_DPORT: + data = pr->dport; + data_m = pr->dport_m; + break; + case RTL838X_TEMPLATE_FIELD_ICMP_IGMP: + data = pr->icmp_igmp; + data_m = pr->icmp_igmp_m; + break; + default: + pr_debug("%s: unknown field %d\n", __func__, field_type); + continue; + } + if (!(i % 2)) { + r[5 - i / 2] = data; + r[12 - i / 2] = data_m; + } else { + r[5 - i / 2] |= ((u32)data) << 16; + r[12 - i / 2] |= ((u32)data_m) << 16; + } + } +} + +/* Creates the intermediate representation of the templated match-fields of the + * PIE rule in the pie_rule structure by reading the raw data fields in the + * raw register space r[]. + * The register space configuration size is identical for the RTL8380/90 and RTL9300, + * however the RTL9310 has 2 more registers / fields and the physical field-ids + */ +static void rtl838x_read_pie_templated(u32 r[], struct pie_rule *pr, enum rtl838x_template_field_id t[]) +{ + for (int i = 0; i < N_FIXED_FIELDS; i++) { + enum rtl838x_template_field_id field_type = t[i]; + u16 data, data_m; + + field_type = t[i]; + if (!(i % 2)) { + data = r[5 - i / 2]; + data_m = r[12 - i / 2]; + } else { + data = r[5 - i / 2] >> 16; + data_m = r[12 - i / 2] >> 16; + } + + switch (field_type) { + case RTL838X_TEMPLATE_FIELD_SPM0: + pr->spm = (pr->spn << 16) | data; + pr->spm_m = (pr->spn << 16) | data_m; + break; + case RTL838X_TEMPLATE_FIELD_SPM1: + pr->spm = data; + pr->spm_m = data_m; + break; + case RTL838X_TEMPLATE_FIELD_OTAG: + pr->otag = data; + pr->otag_m = data_m; + break; + case RTL838X_TEMPLATE_FIELD_SMAC0: + pr->smac[4] = data >> 8; + pr->smac[5] = data; + pr->smac_m[4] = data >> 8; + pr->smac_m[5] = data; + break; + case RTL838X_TEMPLATE_FIELD_SMAC1: + pr->smac[2] = data >> 8; + pr->smac[3] = data; + pr->smac_m[2] = data >> 8; + pr->smac_m[3] = data; + break; + case RTL838X_TEMPLATE_FIELD_SMAC2: + pr->smac[0] = data >> 8; + pr->smac[1] = data; + pr->smac_m[0] = data >> 8; + pr->smac_m[1] = data; + break; + case RTL838X_TEMPLATE_FIELD_DMAC0: + pr->dmac[4] = data >> 8; + pr->dmac[5] = data; + pr->dmac_m[4] = data >> 8; + pr->dmac_m[5] = data; + break; + case RTL838X_TEMPLATE_FIELD_DMAC1: + pr->dmac[2] = data >> 8; + pr->dmac[3] = data; + pr->dmac_m[2] = data >> 8; + pr->dmac_m[3] = data; + break; + case RTL838X_TEMPLATE_FIELD_DMAC2: + pr->dmac[0] = data >> 8; + pr->dmac[1] = data; + pr->dmac_m[0] = data >> 8; + pr->dmac_m[1] = data; + break; + case RTL838X_TEMPLATE_FIELD_ETHERTYPE: + pr->ethertype = data; + pr->ethertype_m = data_m; + break; + case RTL838X_TEMPLATE_FIELD_ITAG: + pr->itag = data; + pr->itag_m = data_m; + break; + case RTL838X_TEMPLATE_FIELD_RANGE_CHK: + pr->field_range_check = data; + pr->field_range_check_m = data_m; + break; + case RTL838X_TEMPLATE_FIELD_SIP0: + pr->sip = data; + pr->sip_m = data_m; + break; + case RTL838X_TEMPLATE_FIELD_SIP1: + pr->sip = (pr->sip << 16) | data; + pr->sip_m = (pr->sip << 16) | data_m; + break; + case RTL838X_TEMPLATE_FIELD_SIP2: + pr->is_ipv6 = true; + /* Make use of limitiations on the position of the match values */ + ipv6_addr_set(&pr->sip6, pr->sip, r[5 - i / 2], + r[4 - i / 2], r[3 - i / 2]); + ipv6_addr_set(&pr->sip6_m, pr->sip_m, r[5 - i / 2], + r[4 - i / 2], r[3 - i / 2]); + case RTL838X_TEMPLATE_FIELD_SIP3: + case RTL838X_TEMPLATE_FIELD_SIP4: + case RTL838X_TEMPLATE_FIELD_SIP5: + case RTL838X_TEMPLATE_FIELD_SIP6: + case RTL838X_TEMPLATE_FIELD_SIP7: + break; + case RTL838X_TEMPLATE_FIELD_DIP0: + pr->dip = data; + pr->dip_m = data_m; + break; + case RTL838X_TEMPLATE_FIELD_DIP1: + pr->dip = (pr->dip << 16) | data; + pr->dip_m = (pr->dip << 16) | data_m; + break; + case RTL838X_TEMPLATE_FIELD_DIP2: + pr->is_ipv6 = true; + ipv6_addr_set(&pr->dip6, pr->dip, r[5 - i / 2], + r[4 - i / 2], r[3 - i / 2]); + ipv6_addr_set(&pr->dip6_m, pr->dip_m, r[5 - i / 2], + r[4 - i / 2], r[3 - i / 2]); + case RTL838X_TEMPLATE_FIELD_DIP3: + case RTL838X_TEMPLATE_FIELD_DIP4: + case RTL838X_TEMPLATE_FIELD_DIP5: + case RTL838X_TEMPLATE_FIELD_DIP6: + case RTL838X_TEMPLATE_FIELD_DIP7: + break; + case RTL838X_TEMPLATE_FIELD_IP_TOS_PROTO: + pr->tos_proto = data; + pr->tos_proto_m = data_m; + break; + case RTL838X_TEMPLATE_FIELD_L4_SPORT: + pr->sport = data; + pr->sport_m = data_m; + break; + case RTL838X_TEMPLATE_FIELD_L4_DPORT: + pr->dport = data; + pr->dport_m = data_m; + break; + case RTL838X_TEMPLATE_FIELD_ICMP_IGMP: + pr->icmp_igmp = data; + pr->icmp_igmp_m = data_m; + break; + default: + pr_debug("%s: unknown field %d\n", __func__, field_type); + } + } +} + +static void rtl838x_read_pie_fixed_fields(u32 r[], struct pie_rule *pr) +{ + pr->spmmask_fix = (r[6] >> 22) & 0x3; + pr->spn = (r[6] >> 16) & 0x3f; + pr->mgnt_vlan = (r[6] >> 15) & 1; + pr->dmac_hit_sw = (r[6] >> 14) & 1; + pr->not_first_frag = (r[6] >> 13) & 1; + pr->frame_type_l4 = (r[6] >> 10) & 7; + pr->frame_type = (r[6] >> 8) & 3; + pr->otag_fmt = (r[6] >> 7) & 1; + pr->itag_fmt = (r[6] >> 6) & 1; + pr->otag_exist = (r[6] >> 5) & 1; + pr->itag_exist = (r[6] >> 4) & 1; + pr->frame_type_l2 = (r[6] >> 2) & 3; + pr->tid = r[6] & 3; + + pr->spmmask_fix_m = (r[13] >> 22) & 0x3; + pr->spn_m = (r[13] >> 16) & 0x3f; + pr->mgnt_vlan_m = (r[13] >> 15) & 1; + pr->dmac_hit_sw_m = (r[13] >> 14) & 1; + pr->not_first_frag_m = (r[13] >> 13) & 1; + pr->frame_type_l4_m = (r[13] >> 10) & 7; + pr->frame_type_m = (r[13] >> 8) & 3; + pr->otag_fmt_m = (r[13] >> 7) & 1; + pr->itag_fmt_m = (r[13] >> 6) & 1; + pr->otag_exist_m = (r[13] >> 5) & 1; + pr->itag_exist_m = (r[13] >> 4) & 1; + pr->frame_type_l2_m = (r[13] >> 2) & 3; + pr->tid_m = r[13] & 3; + + pr->valid = r[14] & BIT(31); + pr->cond_not = r[14] & BIT(30); + pr->cond_and1 = r[14] & BIT(29); + pr->cond_and2 = r[14] & BIT(28); + pr->ivalid = r[14] & BIT(27); + + pr->drop = (r[17] >> 14) & 3; + pr->fwd_sel = r[17] & BIT(13); + pr->ovid_sel = r[17] & BIT(12); + pr->ivid_sel = r[17] & BIT(11); + pr->flt_sel = r[17] & BIT(10); + pr->log_sel = r[17] & BIT(9); + pr->rmk_sel = r[17] & BIT(8); + pr->meter_sel = r[17] & BIT(7); + pr->tagst_sel = r[17] & BIT(6); + pr->mir_sel = r[17] & BIT(5); + pr->nopri_sel = r[17] & BIT(4); + pr->cpupri_sel = r[17] & BIT(3); + pr->otpid_sel = r[17] & BIT(2); + pr->itpid_sel = r[17] & BIT(1); + pr->shaper_sel = r[17] & BIT(0); +} + +static void rtl838x_write_pie_fixed_fields(u32 r[], struct pie_rule *pr) +{ + r[6] = ((u32)(pr->spmmask_fix & 0x3)) << 22; + r[6] |= ((u32)(pr->spn & 0x3f)) << 16; + r[6] |= pr->mgnt_vlan ? BIT(15) : 0; + r[6] |= pr->dmac_hit_sw ? BIT(14) : 0; + r[6] |= pr->not_first_frag ? BIT(13) : 0; + r[6] |= ((u32)(pr->frame_type_l4 & 0x7)) << 10; + r[6] |= ((u32)(pr->frame_type & 0x3)) << 8; + r[6] |= pr->otag_fmt ? BIT(7) : 0; + r[6] |= pr->itag_fmt ? BIT(6) : 0; + r[6] |= pr->otag_exist ? BIT(5) : 0; + r[6] |= pr->itag_exist ? BIT(4) : 0; + r[6] |= ((u32)(pr->frame_type_l2 & 0x3)) << 2; + r[6] |= ((u32)(pr->tid & 0x3)); + + r[13] = ((u32)(pr->spmmask_fix_m & 0x3)) << 22; + r[13] |= ((u32)(pr->spn_m & 0x3f)) << 16; + r[13] |= pr->mgnt_vlan_m ? BIT(15) : 0; + r[13] |= pr->dmac_hit_sw_m ? BIT(14) : 0; + r[13] |= pr->not_first_frag_m ? BIT(13) : 0; + r[13] |= ((u32)(pr->frame_type_l4_m & 0x7)) << 10; + r[13] |= ((u32)(pr->frame_type_m & 0x3)) << 8; + r[13] |= pr->otag_fmt_m ? BIT(7) : 0; + r[13] |= pr->itag_fmt_m ? BIT(6) : 0; + r[13] |= pr->otag_exist_m ? BIT(5) : 0; + r[13] |= pr->itag_exist_m ? BIT(4) : 0; + r[13] |= ((u32)(pr->frame_type_l2_m & 0x3)) << 2; + r[13] |= ((u32)(pr->tid_m & 0x3)); + + r[14] = pr->valid ? BIT(31) : 0; + r[14] |= pr->cond_not ? BIT(30) : 0; + r[14] |= pr->cond_and1 ? BIT(29) : 0; + r[14] |= pr->cond_and2 ? BIT(28) : 0; + r[14] |= pr->ivalid ? BIT(27) : 0; + + if (pr->drop) + r[17] = 0x1 << 14; /* Standard drop action */ + else + r[17] = 0; + r[17] |= pr->fwd_sel ? BIT(13) : 0; + r[17] |= pr->ovid_sel ? BIT(12) : 0; + r[17] |= pr->ivid_sel ? BIT(11) : 0; + r[17] |= pr->flt_sel ? BIT(10) : 0; + r[17] |= pr->log_sel ? BIT(9) : 0; + r[17] |= pr->rmk_sel ? BIT(8) : 0; + r[17] |= pr->meter_sel ? BIT(7) : 0; + r[17] |= pr->tagst_sel ? BIT(6) : 0; + r[17] |= pr->mir_sel ? BIT(5) : 0; + r[17] |= pr->nopri_sel ? BIT(4) : 0; + r[17] |= pr->cpupri_sel ? BIT(3) : 0; + r[17] |= pr->otpid_sel ? BIT(2) : 0; + r[17] |= pr->itpid_sel ? BIT(1) : 0; + r[17] |= pr->shaper_sel ? BIT(0) : 0; +} + +static int rtl838x_write_pie_action(u32 r[], struct pie_rule *pr) +{ + u16 *aif = (u16 *)&r[17]; + u16 data; + int fields_used = 0; + + aif--; + + pr_debug("%s, at %08x\n", __func__, (u32)aif); + /* Multiple actions can be linked to a match of a PIE rule, + * they have different precedence depending on their type and this precedence + * defines which Action Information Field (0-4) in the IACL table stores + * the additional data of the action (like e.g. the port number a packet is + * forwarded to) + */ + /* TODO: count bits in selectors to limit to a maximum number of actions */ + if (pr->fwd_sel) { /* Forwarding action */ + data = pr->fwd_act << 13; + data |= pr->fwd_data; + data |= pr->bypass_all ? BIT(12) : 0; + data |= pr->bypass_ibc_sc ? BIT(11) : 0; + data |= pr->bypass_igr_stp ? BIT(10) : 0; + *aif-- = data; + fields_used++; + } + + if (pr->ovid_sel) { /* Outer VID action */ + data = (pr->ovid_act & 0x3) << 12; + data |= pr->ovid_data; + *aif-- = data; + fields_used++; + } + + if (pr->ivid_sel) { /* Inner VID action */ + data = (pr->ivid_act & 0x3) << 12; + data |= pr->ivid_data; + *aif-- = data; + fields_used++; + } + + if (pr->flt_sel) { /* Filter action */ + *aif-- = pr->flt_data; + fields_used++; + } + + if (pr->log_sel) { /* Log action */ + if (fields_used >= 4) + return -1; + *aif-- = pr->log_data; + fields_used++; + } + + if (pr->rmk_sel) { /* Remark action */ + if (fields_used >= 4) + return -1; + *aif-- = pr->rmk_data; + fields_used++; + } + + if (pr->meter_sel) { /* Meter action */ + if (fields_used >= 4) + return -1; + *aif-- = pr->meter_data; + fields_used++; + } + + if (pr->tagst_sel) { /* Egress Tag Status action */ + if (fields_used >= 4) + return -1; + *aif-- = pr->tagst_data; + fields_used++; + } + + if (pr->mir_sel) { /* Mirror action */ + if (fields_used >= 4) + return -1; + *aif-- = pr->mir_data; + fields_used++; + } + + if (pr->nopri_sel) { /* Normal Priority action */ + if (fields_used >= 4) + return -1; + *aif-- = pr->nopri_data; + fields_used++; + } + + if (pr->cpupri_sel) { /* CPU Priority action */ + if (fields_used >= 4) + return -1; + *aif-- = pr->nopri_data; + fields_used++; + } + + if (pr->otpid_sel) { /* OTPID action */ + if (fields_used >= 4) + return -1; + *aif-- = pr->otpid_data; + fields_used++; + } + + if (pr->itpid_sel) { /* ITPID action */ + if (fields_used >= 4) + return -1; + *aif-- = pr->itpid_data; + fields_used++; + } + + if (pr->shaper_sel) { /* Traffic shaper action */ + if (fields_used >= 4) + return -1; + *aif-- = pr->shaper_data; + fields_used++; + } + + return 0; +} + +static void rtl838x_read_pie_action(u32 r[], struct pie_rule *pr) +{ + u16 *aif = (u16 *)&r[17]; + + aif--; + + pr_debug("%s, at %08x\n", __func__, (u32)aif); + if (pr->drop) + pr_debug("%s: Action Drop: %d", __func__, pr->drop); + + if (pr->fwd_sel) { /* Forwarding action */ + pr->fwd_act = *aif >> 13; + pr->fwd_data = *aif--; + pr->bypass_all = pr->fwd_data & BIT(12); + pr->bypass_ibc_sc = pr->fwd_data & BIT(11); + pr->bypass_igr_stp = pr->fwd_data & BIT(10); + if (pr->bypass_all || pr->bypass_ibc_sc || pr->bypass_igr_stp) + pr->bypass_sel = true; + } + if (pr->ovid_sel) /* Outer VID action */ + pr->ovid_data = *aif--; + if (pr->ivid_sel) /* Inner VID action */ + pr->ivid_data = *aif--; + if (pr->flt_sel) /* Filter action */ + pr->flt_data = *aif--; + if (pr->log_sel) /* Log action */ + pr->log_data = *aif--; + if (pr->rmk_sel) /* Remark action */ + pr->rmk_data = *aif--; + if (pr->meter_sel) /* Meter action */ + pr->meter_data = *aif--; + if (pr->tagst_sel) /* Egress Tag Status action */ + pr->tagst_data = *aif--; + if (pr->mir_sel) /* Mirror action */ + pr->mir_data = *aif--; + if (pr->nopri_sel) /* Normal Priority action */ + pr->nopri_data = *aif--; + if (pr->cpupri_sel) /* CPU Priority action */ + pr->nopri_data = *aif--; + if (pr->otpid_sel) /* OTPID action */ + pr->otpid_data = *aif--; + if (pr->itpid_sel) /* ITPID action */ + pr->itpid_data = *aif--; + if (pr->shaper_sel) /* Traffic shaper action */ + pr->shaper_data = *aif--; +} + +static void rtl838x_pie_rule_dump_raw(u32 r[]) +{ + pr_debug("Raw IACL table entry:\n"); + pr_debug("Match : %08x %08x %08x %08x %08x %08x\n", r[0], r[1], r[2], r[3], r[4], r[5]); + pr_debug("Fixed : %08x\n", r[6]); + pr_debug("Match M: %08x %08x %08x %08x %08x %08x\n", r[7], r[8], r[9], r[10], r[11], r[12]); + pr_debug("Fixed M: %08x\n", r[13]); + pr_debug("AIF : %08x %08x %08x\n", r[14], r[15], r[16]); + pr_debug("Sel : %08x\n", r[17]); +} + +// Currently not used +// static void rtl838x_pie_rule_dump(struct pie_rule *pr) +// { +// pr_debug("Drop: %d, fwd: %d, ovid: %d, ivid: %d, flt: %d, log: %d, rmk: %d, meter: %d tagst: %d, mir: %d, nopri: %d, cpupri: %d, otpid: %d, itpid: %d, shape: %d\n", +// pr->drop, pr->fwd_sel, pr->ovid_sel, pr->ivid_sel, pr->flt_sel, pr->log_sel, pr->rmk_sel, pr->log_sel, pr->tagst_sel, pr->mir_sel, pr->nopri_sel, +// pr->cpupri_sel, pr->otpid_sel, pr->itpid_sel, pr->shaper_sel); +// if (pr->fwd_sel) +// pr_debug("FWD: %08x\n", pr->fwd_data); +// pr_debug("TID: %x, %x\n", pr->tid, pr->tid_m); +// } + +int rtl838x_pie_rule_read(struct rtl838x_switch_priv *priv, int idx, struct pie_rule *pr) +{ + int tbl = otto_table_acquire(RTL8380_TBL_IACL); + u32 r[18]; + int block = idx / PIE_BLOCK_SIZE; + u32 t_select = sw_r32(RTL838X_ACL_BLK_TMPLTE_CTRL(block)); + + memset(pr, 0, sizeof(*pr)); + __otto_table_read(tbl, idx, &r); + + otto_table_release(tbl); + + rtl838x_read_pie_fixed_fields(r, pr); + if (!pr->valid) + return 0; + + pr_debug("%s: template_selectors %08x, tid: %d\n", __func__, t_select, pr->tid); + rtl838x_pie_rule_dump_raw(r); + + rtl838x_read_pie_templated(r, pr, rtl838x_fixed_templates[(t_select >> (pr->tid * 3)) & 0x7]); + + rtl838x_read_pie_action(r, pr); + + return 0; +} + +int rtl838x_pie_rule_write(struct rtl838x_switch_priv *priv, int idx, struct pie_rule *pr) +{ + int tbl = otto_table_acquire(RTL8380_TBL_IACL); + u32 r[18]; + int err; + int block = idx / PIE_BLOCK_SIZE; + u32 t_select = sw_r32(RTL838X_ACL_BLK_TMPLTE_CTRL(block)); + + pr_debug("%s: %d, t_select: %08x\n", __func__, idx, t_select); + + for (int i = 0; i < 18; i++) + r[i] = 0; + + if (!pr->valid) { + err = -EINVAL; + pr_err("Rule invalid\n"); + goto errout; + } + + rtl838x_write_pie_fixed_fields(r, pr); + + pr_debug("%s: template %d\n", __func__, (t_select >> (pr->tid * 3)) & 0x7); + rtl838x_write_pie_templated(r, pr, rtl838x_fixed_templates[(t_select >> (pr->tid * 3)) & 0x7]); + + err = rtl838x_write_pie_action(r, pr); + if (err) { + pr_err("Rule actions too complex\n"); + goto errout; + } + +/* rtl838x_pie_rule_dump_raw(r); */ + + __otto_table_write(tbl, idx, &r); + otto_table_release(tbl); + + return err; + +errout: + /* Leave no half-built rule behind: commit an empty entry. The write + * used to go out with the data registers untouched, which committed + * whatever the previous table access had left in them. + */ + memset(r, 0, sizeof(r)); + __otto_table_write(tbl, idx, &r); + otto_table_release(tbl); + + return err; +} + +static bool rtl838x_pie_templ_has(int t, enum rtl838x_template_field_id field_type) +{ + enum rtl838x_template_field_id ft; + + for (int i = 0; i < N_FIXED_FIELDS; i++) { + ft = rtl838x_fixed_templates[t][i]; + if (field_type == ft) + return true; + } + + return false; +} + +static int rtl838x_pie_verify_template(struct rtl838x_switch_priv *priv, + struct pie_rule *pr, int t, int block) +{ + int i; + + if (!pr->is_ipv6 && pr->sip_m && !rtl838x_pie_templ_has(t, RTL838X_TEMPLATE_FIELD_SIP0)) + return -1; + + if (!pr->is_ipv6 && pr->dip_m && !rtl838x_pie_templ_has(t, RTL838X_TEMPLATE_FIELD_DIP0)) + return -1; + + if (pr->is_ipv6) { + if ((pr->sip6_m.s6_addr32[0] || + pr->sip6_m.s6_addr32[1] || + pr->sip6_m.s6_addr32[2] || + pr->sip6_m.s6_addr32[3]) && + !rtl838x_pie_templ_has(t, RTL838X_TEMPLATE_FIELD_SIP2)) + return -1; + if ((pr->dip6_m.s6_addr32[0] || + pr->dip6_m.s6_addr32[1] || + pr->dip6_m.s6_addr32[2] || + pr->dip6_m.s6_addr32[3]) && + !rtl838x_pie_templ_has(t, RTL838X_TEMPLATE_FIELD_DIP2)) + return -1; + } + + if (ether_addr_to_u64(pr->smac_m) && !rtl838x_pie_templ_has(t, RTL838X_TEMPLATE_FIELD_SMAC0)) + return -1; + + if (ether_addr_to_u64(pr->dmac_m) && !rtl838x_pie_templ_has(t, RTL838X_TEMPLATE_FIELD_DMAC0)) + return -1; + + if (pr->itag_m && !rtl838x_pie_templ_has(t, RTL838X_TEMPLATE_FIELD_ITAG)) + return -1; + + if (pr->sport_m && !rtl838x_pie_templ_has(t, RTL838X_TEMPLATE_FIELD_L4_SPORT)) + return -1; + + if (pr->dport_m && !rtl838x_pie_templ_has(t, RTL838X_TEMPLATE_FIELD_L4_DPORT)) + return -1; + + /* TODO: Check more */ + + i = find_first_zero_bit(&priv->pie_use_bm[block * 4], PIE_BLOCK_SIZE); + + if (i >= PIE_BLOCK_SIZE) + return -1; + + return i + PIE_BLOCK_SIZE * block; +} + +int rtl838x_pie_rule_add(struct rtl838x_switch_priv *priv, struct pie_rule *pr) +{ + int idx, block, j; + + pr_debug("In %s\n", __func__); + + mutex_lock(&priv->pie_mutex); + + for (block = 0; block < priv->r->n_pie_blocks; block++) { + for (j = 0; j < 3; j++) { + int t = (sw_r32(RTL838X_ACL_BLK_TMPLTE_CTRL(block)) >> (j * 3)) & 0x7; + + pr_debug("Testing block %d, template %d, template id %d\n", block, j, t); + idx = rtl838x_pie_verify_template(priv, pr, t, block); + if (idx >= 0) + break; + } + if (j < 3) + break; + } + + if (block >= priv->r->n_pie_blocks) { + mutex_unlock(&priv->pie_mutex); + return -EOPNOTSUPP; + } + + pr_debug("Using block: %d, index %d, template-id %d\n", block, idx, j); + set_bit(idx, priv->pie_use_bm); + + pr->valid = true; + pr->tid = j; /* Mapped to template number */ + pr->tid_m = 0x3; + pr->id = idx; + + rtl838x_pie_lookup_enable(priv, idx); + rtl838x_pie_rule_write(priv, idx, pr); + + mutex_unlock(&priv->pie_mutex); + + return 0; +} + +void rtl838x_pie_rule_rm(struct rtl838x_switch_priv *priv, struct pie_rule *pr) +{ + int idx = pr->id; + + rtl838x_pie_rule_del(priv, idx, idx); + clear_bit(idx, priv->pie_use_bm); +} + +/* Initializes the Packet Inspection Engine: + * powers it up, enables default matching templates for all blocks + * and clears all rules possibly installed by u-boot + */ +void rtl838x_pie_init(struct rtl838x_switch_priv *priv) +{ + u32 template_selectors; + + mutex_init(&priv->pie_mutex); + + /* Enable ACL lookup on all ports, including CPU_PORT */ + for (int i = 0; i <= priv->r->cpu_port; i++) + sw_w32(1, RTL838X_ACL_PORT_LOOKUP_CTRL(i)); + + /* Power on all PIE blocks */ + for (int i = 0; i < priv->r->n_pie_blocks; i++) + sw_w32_mask(0, BIT(i), RTL838X_ACL_BLK_PWR_CTRL); + + /* Include IPG in metering */ + sw_w32(1, RTL838X_METER_GLB_CTRL); + + /* Delete all present rules */ + rtl838x_pie_rule_del(priv, 0, priv->r->n_pie_blocks * PIE_BLOCK_SIZE - 1); + + /* Routing bypasses source port filter */ + sw_w32_mask(0, 1, RTL838X_DMY_REG27); + + /* Enable predefined templates 0, 1 and 2 for even blocks */ + template_selectors = 0 | (1 << 3) | (2 << 6); + for (int i = 0; i < 6; i += 2) + sw_w32(template_selectors, RTL838X_ACL_BLK_TMPLTE_CTRL(i)); + + /* Enable predefined templates 0, 3 and 4 (IPv6 support) for odd blocks */ + template_selectors = 0 | (3 << 3) | (4 << 6); + for (int i = 1; i < priv->r->n_pie_blocks; i += 2) + sw_w32(template_selectors, RTL838X_ACL_BLK_TMPLTE_CTRL(i)); + + /* Group each pair of physical blocks together to a logical block */ + sw_w32(0b10101010101, RTL838X_ACL_BLK_GROUP_CTRL); +} + +/* RTL839X */ + +/* Definition of the RTL839X-specific template field IDs as used in the PIE */ +enum rtl839x_template_field_id { + RTL839X_TEMPLATE_FIELD_SPMMASK = 0, + RTL839X_TEMPLATE_FIELD_SPM0 = 1, /* Source portmask ports 0-15 */ + RTL839X_TEMPLATE_FIELD_SPM1 = 2, /* Source portmask ports 16-31 */ + RTL839X_TEMPLATE_FIELD_SPM2 = 3, /* Source portmask ports 32-47 */ + RTL839X_TEMPLATE_FIELD_SPM3 = 4, /* Source portmask ports 48-56 */ + RTL839X_TEMPLATE_FIELD_DMAC0 = 5, /* Destination MAC [15:0] */ + RTL839X_TEMPLATE_FIELD_DMAC1 = 6, /* Destination MAC [31:16] */ + RTL839X_TEMPLATE_FIELD_DMAC2 = 7, /* Destination MAC [47:32] */ + RTL839X_TEMPLATE_FIELD_SMAC0 = 8, /* Source MAC [15:0] */ + RTL839X_TEMPLATE_FIELD_SMAC1 = 9, /* Source MAC [31:16] */ + RTL839X_TEMPLATE_FIELD_SMAC2 = 10, /* Source MAC [47:32] */ + RTL839X_TEMPLATE_FIELD_ETHERTYPE = 11, /* Ethernet frame type field */ + /* Field-ID 12 is not used */ + RTL839X_TEMPLATE_FIELD_OTAG = 13, + RTL839X_TEMPLATE_FIELD_ITAG = 14, + RTL839X_TEMPLATE_FIELD_SIP0 = 15, + RTL839X_TEMPLATE_FIELD_SIP1 = 16, + RTL839X_TEMPLATE_FIELD_DIP0 = 17, + RTL839X_TEMPLATE_FIELD_DIP1 = 18, + RTL839X_TEMPLATE_FIELD_IP_TOS_PROTO = 19, + RTL839X_TEMPLATE_FIELD_IP_FLAG = 20, + RTL839X_TEMPLATE_FIELD_L4_SPORT = 21, + RTL839X_TEMPLATE_FIELD_L4_DPORT = 22, + RTL839X_TEMPLATE_FIELD_L34_HEADER = 23, + RTL839X_TEMPLATE_FIELD_ICMP_IGMP = 24, + RTL839X_TEMPLATE_FIELD_VID_RANG0 = 25, + RTL839X_TEMPLATE_FIELD_VID_RANG1 = 26, + RTL839X_TEMPLATE_FIELD_L4_PORT_RANG = 27, + RTL839X_TEMPLATE_FIELD_FIELD_SELECTOR_VALID = 28, + RTL839X_TEMPLATE_FIELD_FIELD_SELECTOR_0 = 29, + RTL839X_TEMPLATE_FIELD_FIELD_SELECTOR_1 = 30, + RTL839X_TEMPLATE_FIELD_FIELD_SELECTOR_2 = 31, + RTL839X_TEMPLATE_FIELD_FIELD_SELECTOR_3 = 32, + RTL839X_TEMPLATE_FIELD_FIELD_SELECTOR_4 = 33, + RTL839X_TEMPLATE_FIELD_FIELD_SELECTOR_5 = 34, + RTL839X_TEMPLATE_FIELD_SIP2 = 35, + RTL839X_TEMPLATE_FIELD_SIP3 = 36, + RTL839X_TEMPLATE_FIELD_SIP4 = 37, + RTL839X_TEMPLATE_FIELD_SIP5 = 38, + RTL839X_TEMPLATE_FIELD_SIP6 = 39, + RTL839X_TEMPLATE_FIELD_SIP7 = 40, + RTL839X_TEMPLATE_FIELD_OLABEL = 41, + RTL839X_TEMPLATE_FIELD_ILABEL = 42, + RTL839X_TEMPLATE_FIELD_OILABEL = 43, + RTL839X_TEMPLATE_FIELD_DPMMASK = 44, + RTL839X_TEMPLATE_FIELD_DPM0 = 45, + RTL839X_TEMPLATE_FIELD_DPM1 = 46, + RTL839X_TEMPLATE_FIELD_DPM2 = 47, + RTL839X_TEMPLATE_FIELD_DPM3 = 48, + RTL839X_TEMPLATE_FIELD_L2DPM0 = 49, + RTL839X_TEMPLATE_FIELD_L2DPM1 = 50, + RTL839X_TEMPLATE_FIELD_L2DPM2 = 51, + RTL839X_TEMPLATE_FIELD_L2DPM3 = 52, + RTL839X_TEMPLATE_FIELD_IVLAN = 53, + RTL839X_TEMPLATE_FIELD_OVLAN = 54, + RTL839X_TEMPLATE_FIELD_FWD_VID = 55, + RTL839X_TEMPLATE_FIELD_DIP2 = 56, + RTL839X_TEMPLATE_FIELD_DIP3 = 57, + RTL839X_TEMPLATE_FIELD_DIP4 = 58, + RTL839X_TEMPLATE_FIELD_DIP5 = 59, + RTL839X_TEMPLATE_FIELD_DIP6 = 60, + RTL839X_TEMPLATE_FIELD_DIP7 = 61, +}; + +/* Number of fixed templates predefined in the SoC */ +#define RTL839X_N_FIXED_TEMPLATES 5 +static enum rtl839x_template_field_id rtl839x_fixed_templates[RTL839X_N_FIXED_TEMPLATES][N_FIXED_FIELDS] = { + { + RTL839X_TEMPLATE_FIELD_SPM0, RTL839X_TEMPLATE_FIELD_SPM1, RTL839X_TEMPLATE_FIELD_ITAG, + RTL839X_TEMPLATE_FIELD_SMAC0, RTL839X_TEMPLATE_FIELD_SMAC1, RTL839X_TEMPLATE_FIELD_SMAC2, + RTL839X_TEMPLATE_FIELD_DMAC0, RTL839X_TEMPLATE_FIELD_DMAC1, RTL839X_TEMPLATE_FIELD_DMAC2, + RTL839X_TEMPLATE_FIELD_ETHERTYPE, RTL839X_TEMPLATE_FIELD_SPM2, RTL839X_TEMPLATE_FIELD_SPM3 + }, { + RTL839X_TEMPLATE_FIELD_SIP0, RTL839X_TEMPLATE_FIELD_SIP1, RTL839X_TEMPLATE_FIELD_DIP0, + RTL839X_TEMPLATE_FIELD_DIP1, RTL839X_TEMPLATE_FIELD_IP_TOS_PROTO, RTL839X_TEMPLATE_FIELD_L4_SPORT, + RTL839X_TEMPLATE_FIELD_L4_DPORT, RTL839X_TEMPLATE_FIELD_ICMP_IGMP, RTL839X_TEMPLATE_FIELD_SPM0, + RTL839X_TEMPLATE_FIELD_SPM1, RTL839X_TEMPLATE_FIELD_SPM2, RTL839X_TEMPLATE_FIELD_SPM3 + }, { + RTL839X_TEMPLATE_FIELD_DMAC0, RTL839X_TEMPLATE_FIELD_DMAC1, RTL839X_TEMPLATE_FIELD_DMAC2, + RTL839X_TEMPLATE_FIELD_ITAG, RTL839X_TEMPLATE_FIELD_ETHERTYPE, RTL839X_TEMPLATE_FIELD_IP_TOS_PROTO, + RTL839X_TEMPLATE_FIELD_L4_DPORT, RTL839X_TEMPLATE_FIELD_L4_SPORT, RTL839X_TEMPLATE_FIELD_SIP0, + RTL839X_TEMPLATE_FIELD_SIP1, RTL839X_TEMPLATE_FIELD_DIP0, RTL839X_TEMPLATE_FIELD_DIP1 + }, { + RTL839X_TEMPLATE_FIELD_DIP0, RTL839X_TEMPLATE_FIELD_DIP1, RTL839X_TEMPLATE_FIELD_DIP2, + RTL839X_TEMPLATE_FIELD_DIP3, RTL839X_TEMPLATE_FIELD_DIP4, RTL839X_TEMPLATE_FIELD_DIP5, + RTL839X_TEMPLATE_FIELD_DIP6, RTL839X_TEMPLATE_FIELD_DIP7, RTL839X_TEMPLATE_FIELD_L4_DPORT, + RTL839X_TEMPLATE_FIELD_L4_SPORT, RTL839X_TEMPLATE_FIELD_ICMP_IGMP, RTL839X_TEMPLATE_FIELD_IP_TOS_PROTO + }, { + RTL839X_TEMPLATE_FIELD_SIP0, RTL839X_TEMPLATE_FIELD_SIP1, RTL839X_TEMPLATE_FIELD_SIP2, + RTL839X_TEMPLATE_FIELD_SIP3, RTL839X_TEMPLATE_FIELD_SIP4, RTL839X_TEMPLATE_FIELD_SIP5, + RTL839X_TEMPLATE_FIELD_SIP6, RTL839X_TEMPLATE_FIELD_SIP7, RTL839X_TEMPLATE_FIELD_SPM0, + RTL839X_TEMPLATE_FIELD_SPM1, RTL839X_TEMPLATE_FIELD_SPM2, RTL839X_TEMPLATE_FIELD_SPM3 + }, +}; + +static void rtl839x_pie_lookup_enable(struct rtl838x_switch_priv *priv, int index) +{ + int block = index / PIE_BLOCK_SIZE; + + sw_w32_mask(0, BIT(block), RTL839X_ACL_BLK_LOOKUP_CTRL); +} + +/* Delete a range of Packet Inspection Engine rules */ +static int rtl839x_pie_rule_del(struct rtl838x_switch_priv *priv, int index_from, int index_to) +{ + u32 v = (index_from << 1) | (index_to << 13) | BIT(0); + + pr_debug("%s: from %d to %d\n", __func__, index_from, index_to); + mutex_lock(&priv->reg_mutex); + + /* Write from-to and execute bit into control register */ + sw_w32(v, RTL839X_ACL_CLR_CTRL); + + /* Wait until command has completed */ + do { + } while (sw_r32(RTL839X_ACL_CLR_CTRL) & BIT(0)); + + mutex_unlock(&priv->reg_mutex); + + return 0; +} + +/* Reads the intermediate representation of the templated match-fields of the + * PIE rule in the pie_rule structure and fills in the raw data fields in the + * raw register space r[]. + * The register space configuration size is identical for the RTL8380/90 and RTL9300, + * however the RTL9310 has 2 more registers / fields and the physical field-ids are different + * on all SoCs + * On the RTL8390 the template mask registers are not word-aligned! + */ +static void rtl839x_write_pie_templated(u32 r[], struct pie_rule *pr, enum rtl839x_template_field_id t[]) +{ + for (int i = 0; i < N_FIXED_FIELDS; i++) { + enum rtl839x_template_field_id field_type = t[i]; + u16 data = 0, data_m = 0; + + switch (field_type) { + case RTL839X_TEMPLATE_FIELD_SPM0: + data = pr->spm; + data_m = pr->spm_m; + break; + case RTL839X_TEMPLATE_FIELD_SPM1: + data = pr->spm >> 16; + data_m = pr->spm_m >> 16; + break; + case RTL839X_TEMPLATE_FIELD_SPM2: + data = pr->spm >> 32; + data_m = pr->spm_m >> 32; + break; + case RTL839X_TEMPLATE_FIELD_SPM3: + data = pr->spm >> 48; + data_m = pr->spm_m >> 48; + break; + case RTL839X_TEMPLATE_FIELD_OTAG: + data = pr->otag; + data_m = pr->otag_m; + break; + case RTL839X_TEMPLATE_FIELD_SMAC0: + data = pr->smac[4]; + data = (data << 8) | pr->smac[5]; + data_m = pr->smac_m[4]; + data_m = (data_m << 8) | pr->smac_m[5]; + break; + case RTL839X_TEMPLATE_FIELD_SMAC1: + data = pr->smac[2]; + data = (data << 8) | pr->smac[3]; + data_m = pr->smac_m[2]; + data_m = (data_m << 8) | pr->smac_m[3]; + break; + case RTL839X_TEMPLATE_FIELD_SMAC2: + data = pr->smac[0]; + data = (data << 8) | pr->smac[1]; + data_m = pr->smac_m[0]; + data_m = (data_m << 8) | pr->smac_m[1]; + break; + case RTL839X_TEMPLATE_FIELD_DMAC0: + data = pr->dmac[4]; + data = (data << 8) | pr->dmac[5]; + data_m = pr->dmac_m[4]; + data_m = (data_m << 8) | pr->dmac_m[5]; + break; + case RTL839X_TEMPLATE_FIELD_DMAC1: + data = pr->dmac[2]; + data = (data << 8) | pr->dmac[3]; + data_m = pr->dmac_m[2]; + data_m = (data_m << 8) | pr->dmac_m[3]; + break; + case RTL839X_TEMPLATE_FIELD_DMAC2: + data = pr->dmac[0]; + data = (data << 8) | pr->dmac[1]; + data_m = pr->dmac_m[0]; + data_m = (data_m << 8) | pr->dmac_m[1]; + break; + case RTL839X_TEMPLATE_FIELD_ETHERTYPE: + data = pr->ethertype; + data_m = pr->ethertype_m; + break; + case RTL839X_TEMPLATE_FIELD_ITAG: + data = pr->itag; + data_m = pr->itag_m; + break; + case RTL839X_TEMPLATE_FIELD_SIP0: + if (pr->is_ipv6) { + data = pr->sip6.s6_addr16[7]; + data_m = pr->sip6_m.s6_addr16[7]; + } else { + data = pr->sip; + data_m = pr->sip_m; + } + break; + case RTL839X_TEMPLATE_FIELD_SIP1: + if (pr->is_ipv6) { + data = pr->sip6.s6_addr16[6]; + data_m = pr->sip6_m.s6_addr16[6]; + } else { + data = pr->sip >> 16; + data_m = pr->sip_m >> 16; + } + break; + case RTL839X_TEMPLATE_FIELD_SIP2: + case RTL839X_TEMPLATE_FIELD_SIP3: + case RTL839X_TEMPLATE_FIELD_SIP4: + case RTL839X_TEMPLATE_FIELD_SIP5: + case RTL839X_TEMPLATE_FIELD_SIP6: + case RTL839X_TEMPLATE_FIELD_SIP7: + data = pr->sip6.s6_addr16[5 - (field_type - RTL839X_TEMPLATE_FIELD_SIP2)]; + data_m = pr->sip6_m.s6_addr16[5 - (field_type - RTL839X_TEMPLATE_FIELD_SIP2)]; + break; + case RTL839X_TEMPLATE_FIELD_DIP0: + if (pr->is_ipv6) { + data = pr->dip6.s6_addr16[7]; + data_m = pr->dip6_m.s6_addr16[7]; + } else { + data = pr->dip; + data_m = pr->dip_m; + } + break; + case RTL839X_TEMPLATE_FIELD_DIP1: + if (pr->is_ipv6) { + data = pr->dip6.s6_addr16[6]; + data_m = pr->dip6_m.s6_addr16[6]; + } else { + data = pr->dip >> 16; + data_m = pr->dip_m >> 16; + } + break; + case RTL839X_TEMPLATE_FIELD_DIP2: + case RTL839X_TEMPLATE_FIELD_DIP3: + case RTL839X_TEMPLATE_FIELD_DIP4: + case RTL839X_TEMPLATE_FIELD_DIP5: + case RTL839X_TEMPLATE_FIELD_DIP6: + case RTL839X_TEMPLATE_FIELD_DIP7: + data = pr->dip6.s6_addr16[5 - (field_type - RTL839X_TEMPLATE_FIELD_DIP2)]; + data_m = pr->dip6_m.s6_addr16[5 - (field_type - RTL839X_TEMPLATE_FIELD_DIP2)]; + break; + case RTL839X_TEMPLATE_FIELD_IP_TOS_PROTO: + data = pr->tos_proto; + data_m = pr->tos_proto_m; + break; + case RTL839X_TEMPLATE_FIELD_L4_SPORT: + data = pr->sport; + data_m = pr->sport_m; + break; + case RTL839X_TEMPLATE_FIELD_L4_DPORT: + data = pr->dport; + data_m = pr->dport_m; + break; + case RTL839X_TEMPLATE_FIELD_ICMP_IGMP: + data = pr->icmp_igmp; + data_m = pr->icmp_igmp_m; + break; + default: + pr_debug("%s: unknown field %d\n", __func__, field_type); + } + + /* On the RTL8390, the mask fields are not word aligned! */ + if (!(i % 2)) { + r[5 - i / 2] = data; + r[12 - i / 2] |= ((u32)data_m << 8); + } else { + r[5 - i / 2] |= ((u32)data) << 16; + r[12 - i / 2] |= ((u32)data_m) << 24; + r[11 - i / 2] |= ((u32)data_m) >> 8; + } + } +} + +/* Creates the intermediate representation of the templated match-fields of the + * PIE rule in the pie_rule structure by reading the raw data fields in the + * raw register space r[]. + * The register space configuration size is identical for the RTL8380/90 and RTL9300, + * however the RTL9310 has 2 more registers / fields and the physical field-ids + * On the RTL8390 the template mask registers are not word-aligned! + */ +static void rtl839x_read_pie_templated(u32 r[], struct pie_rule *pr, enum rtl839x_template_field_id t[]) +{ + for (int i = 0; i < N_FIXED_FIELDS; i++) { + enum rtl839x_template_field_id field_type = t[i]; + u16 data, data_m; + + if (!(i % 2)) { + data = r[5 - i / 2]; + data_m = r[12 - i / 2]; + } else { + data = r[5 - i / 2] >> 16; + data_m = r[12 - i / 2] >> 16; + } + + switch (field_type) { + case RTL839X_TEMPLATE_FIELD_SPM0: + pr->spm = (pr->spn << 16) | data; + pr->spm_m = (pr->spn << 16) | data_m; + break; + case RTL839X_TEMPLATE_FIELD_SPM1: + pr->spm = data; + pr->spm_m = data_m; + break; + case RTL839X_TEMPLATE_FIELD_OTAG: + pr->otag = data; + pr->otag_m = data_m; + break; + case RTL839X_TEMPLATE_FIELD_SMAC0: + pr->smac[4] = data >> 8; + pr->smac[5] = data; + pr->smac_m[4] = data >> 8; + pr->smac_m[5] = data; + break; + case RTL839X_TEMPLATE_FIELD_SMAC1: + pr->smac[2] = data >> 8; + pr->smac[3] = data; + pr->smac_m[2] = data >> 8; + pr->smac_m[3] = data; + break; + case RTL839X_TEMPLATE_FIELD_SMAC2: + pr->smac[0] = data >> 8; + pr->smac[1] = data; + pr->smac_m[0] = data >> 8; + pr->smac_m[1] = data; + break; + case RTL839X_TEMPLATE_FIELD_DMAC0: + pr->dmac[4] = data >> 8; + pr->dmac[5] = data; + pr->dmac_m[4] = data >> 8; + pr->dmac_m[5] = data; + break; + case RTL839X_TEMPLATE_FIELD_DMAC1: + pr->dmac[2] = data >> 8; + pr->dmac[3] = data; + pr->dmac_m[2] = data >> 8; + pr->dmac_m[3] = data; + break; + case RTL839X_TEMPLATE_FIELD_DMAC2: + pr->dmac[0] = data >> 8; + pr->dmac[1] = data; + pr->dmac_m[0] = data >> 8; + pr->dmac_m[1] = data; + break; + case RTL839X_TEMPLATE_FIELD_ETHERTYPE: + pr->ethertype = data; + pr->ethertype_m = data_m; + break; + case RTL839X_TEMPLATE_FIELD_ITAG: + pr->itag = data; + pr->itag_m = data_m; + break; + case RTL839X_TEMPLATE_FIELD_SIP0: + pr->sip = data; + pr->sip_m = data_m; + break; + case RTL839X_TEMPLATE_FIELD_SIP1: + pr->sip = (pr->sip << 16) | data; + pr->sip_m = (pr->sip << 16) | data_m; + break; + case RTL839X_TEMPLATE_FIELD_SIP2: + pr->is_ipv6 = true; + /* Make use of limitiations on the position of the match values */ + ipv6_addr_set(&pr->sip6, pr->sip, r[5 - i / 2], + r[4 - i / 2], r[3 - i / 2]); + ipv6_addr_set(&pr->sip6_m, pr->sip_m, r[5 - i / 2], + r[4 - i / 2], r[3 - i / 2]); + case RTL839X_TEMPLATE_FIELD_SIP3: + case RTL839X_TEMPLATE_FIELD_SIP4: + case RTL839X_TEMPLATE_FIELD_SIP5: + case RTL839X_TEMPLATE_FIELD_SIP6: + case RTL839X_TEMPLATE_FIELD_SIP7: + break; + + case RTL839X_TEMPLATE_FIELD_DIP0: + pr->dip = data; + pr->dip_m = data_m; + break; + + case RTL839X_TEMPLATE_FIELD_DIP1: + pr->dip = (pr->dip << 16) | data; + pr->dip_m = (pr->dip << 16) | data_m; + break; + + case RTL839X_TEMPLATE_FIELD_DIP2: + pr->is_ipv6 = true; + ipv6_addr_set(&pr->dip6, pr->dip, r[5 - i / 2], + r[4 - i / 2], r[3 - i / 2]); + ipv6_addr_set(&pr->dip6_m, pr->dip_m, r[5 - i / 2], + r[4 - i / 2], r[3 - i / 2]); + case RTL839X_TEMPLATE_FIELD_DIP3: + case RTL839X_TEMPLATE_FIELD_DIP4: + case RTL839X_TEMPLATE_FIELD_DIP5: + case RTL839X_TEMPLATE_FIELD_DIP6: + case RTL839X_TEMPLATE_FIELD_DIP7: + break; + case RTL839X_TEMPLATE_FIELD_IP_TOS_PROTO: + pr->tos_proto = data; + pr->tos_proto_m = data_m; + break; + case RTL839X_TEMPLATE_FIELD_L4_SPORT: + pr->sport = data; + pr->sport_m = data_m; + break; + case RTL839X_TEMPLATE_FIELD_L4_DPORT: + pr->dport = data; + pr->dport_m = data_m; + break; + case RTL839X_TEMPLATE_FIELD_ICMP_IGMP: + pr->icmp_igmp = data; + pr->icmp_igmp_m = data_m; + break; + default: + pr_debug("%s: unknown field %d\n", __func__, field_type); + } + } +} + +static void rtl839x_read_pie_fixed_fields(u32 r[], struct pie_rule *pr) +{ + pr->spmmask_fix = (r[6] >> 30) & 0x3; + pr->spn = (r[6] >> 24) & 0x3f; + pr->mgnt_vlan = (r[6] >> 23) & 1; + pr->dmac_hit_sw = (r[6] >> 22) & 1; + pr->not_first_frag = (r[6] >> 21) & 1; + pr->frame_type_l4 = (r[6] >> 18) & 7; + pr->frame_type = (r[6] >> 16) & 3; + pr->otag_fmt = (r[6] >> 15) & 1; + pr->itag_fmt = (r[6] >> 14) & 1; + pr->otag_exist = (r[6] >> 13) & 1; + pr->itag_exist = (r[6] >> 12) & 1; + pr->frame_type_l2 = (r[6] >> 10) & 3; + pr->tid = (r[6] >> 8) & 3; + + pr->spmmask_fix_m = (r[12] >> 6) & 0x3; + pr->spn_m = r[12] & 0x3f; + pr->mgnt_vlan_m = (r[13] >> 31) & 1; + pr->dmac_hit_sw_m = (r[13] >> 30) & 1; + pr->not_first_frag_m = (r[13] >> 29) & 1; + pr->frame_type_l4_m = (r[13] >> 26) & 7; + pr->frame_type_m = (r[13] >> 24) & 3; + pr->otag_fmt_m = (r[13] >> 23) & 1; + pr->itag_fmt_m = (r[13] >> 22) & 1; + pr->otag_exist_m = (r[13] >> 21) & 1; + pr->itag_exist_m = (r[13] >> 20) & 1; + pr->frame_type_l2_m = (r[13] >> 18) & 3; + pr->tid_m = (r[13] >> 16) & 3; + + pr->valid = r[13] & BIT(15); + pr->cond_not = r[13] & BIT(14); + pr->cond_and1 = r[13] & BIT(13); + pr->cond_and2 = r[13] & BIT(12); +} + +static void rtl839x_write_pie_fixed_fields(u32 r[], struct pie_rule *pr) +{ + r[6] = ((u32)(pr->spmmask_fix & 0x3)) << 30; + r[6] |= ((u32)(pr->spn & 0x3f)) << 24; + r[6] |= pr->mgnt_vlan ? BIT(23) : 0; + r[6] |= pr->dmac_hit_sw ? BIT(22) : 0; + r[6] |= pr->not_first_frag ? BIT(21) : 0; + r[6] |= ((u32)(pr->frame_type_l4 & 0x7)) << 18; + r[6] |= ((u32)(pr->frame_type & 0x3)) << 16; + r[6] |= pr->otag_fmt ? BIT(15) : 0; + r[6] |= pr->itag_fmt ? BIT(14) : 0; + r[6] |= pr->otag_exist ? BIT(13) : 0; + r[6] |= pr->itag_exist ? BIT(12) : 0; + r[6] |= ((u32)(pr->frame_type_l2 & 0x3)) << 10; + r[6] |= ((u32)(pr->tid & 0x3)) << 8; + + r[12] |= ((u32)(pr->spmmask_fix_m & 0x3)) << 6; + r[12] |= (u32)(pr->spn_m & 0x3f); + r[13] |= pr->mgnt_vlan_m ? BIT(31) : 0; + r[13] |= pr->dmac_hit_sw_m ? BIT(30) : 0; + r[13] |= pr->not_first_frag_m ? BIT(29) : 0; + r[13] |= ((u32)(pr->frame_type_l4_m & 0x7)) << 26; + r[13] |= ((u32)(pr->frame_type_m & 0x3)) << 24; + r[13] |= pr->otag_fmt_m ? BIT(23) : 0; + r[13] |= pr->itag_fmt_m ? BIT(22) : 0; + r[13] |= pr->otag_exist_m ? BIT(21) : 0; + r[13] |= pr->itag_exist_m ? BIT(20) : 0; + r[13] |= ((u32)(pr->frame_type_l2_m & 0x3)) << 18; + r[13] |= ((u32)(pr->tid_m & 0x3)) << 16; + + r[13] |= pr->valid ? BIT(15) : 0; + r[13] |= pr->cond_not ? BIT(14) : 0; + r[13] |= pr->cond_and1 ? BIT(13) : 0; + r[13] |= pr->cond_and2 ? BIT(12) : 0; +} + +static void rtl839x_write_pie_action(u32 r[], struct pie_rule *pr) +{ + if (pr->drop) { + r[13] |= 0x9; /* Set ACT_MASK_FWD & FWD_ACT = DROP */ + r[13] |= BIT(3); + } else { + r[13] |= pr->fwd_sel ? BIT(3) : 0; + r[13] |= pr->fwd_act; + } + r[13] |= pr->bypass_sel ? BIT(11) : 0; + r[13] |= pr->mpls_sel ? BIT(10) : 0; + r[13] |= pr->nopri_sel ? BIT(9) : 0; + r[13] |= pr->ovid_sel ? BIT(8) : 0; + r[13] |= pr->ivid_sel ? BIT(7) : 0; + r[13] |= pr->meter_sel ? BIT(6) : 0; + r[13] |= pr->mir_sel ? BIT(5) : 0; + r[13] |= pr->log_sel ? BIT(4) : 0; + + r[14] |= ((u32)(pr->fwd_data & 0x3fff)) << 18; + r[14] |= pr->log_octets ? BIT(17) : 0; + r[14] |= ((u32)(pr->log_data & 0x7ff)) << 4; + r[14] |= (pr->mir_data & 0x3) << 3; + r[14] |= ((u32)(pr->meter_data >> 7)) & 0x7; + r[15] |= (u32)(pr->meter_data) << 26; + r[15] |= ((u32)(pr->ivid_act) << 23) & 0x3; + r[15] |= ((u32)(pr->ivid_data) << 9) & 0xfff; + r[15] |= ((u32)(pr->ovid_act) << 6) & 0x3; + r[15] |= ((u32)(pr->ovid_data) >> 4) & 0xff; + r[16] |= ((u32)(pr->ovid_data) & 0xf) << 28; + r[16] |= ((u32)(pr->nopri_data) & 0x7) << 20; + r[16] |= ((u32)(pr->mpls_act) & 0x7) << 20; + r[16] |= ((u32)(pr->mpls_lib_idx) & 0x7) << 20; + r[16] |= pr->bypass_all ? BIT(9) : 0; + r[16] |= pr->bypass_igr_stp ? BIT(8) : 0; + r[16] |= pr->bypass_ibc_sc ? BIT(7) : 0; +} + +static void rtl839x_read_pie_action(u32 r[], struct pie_rule *pr) +{ + if (r[13] & BIT(3)) { /* ACT_MASK_FWD set, is it a drop? */ + if ((r[14] & 0x7) == 1) { + pr->drop = true; + } else { + pr->fwd_sel = true; + pr->fwd_act = r[14] & 0x7; + } + } + + pr->bypass_sel = r[13] & BIT(11); + pr->mpls_sel = r[13] & BIT(10); + pr->nopri_sel = r[13] & BIT(9); + pr->ovid_sel = r[13] & BIT(8); + pr->ivid_sel = r[13] & BIT(7); + pr->meter_sel = r[13] & BIT(6); + pr->mir_sel = r[13] & BIT(5); + pr->log_sel = r[13] & BIT(4); + + /* TODO: Read in data fields */ + + pr->bypass_all = r[16] & BIT(9); + pr->bypass_igr_stp = r[16] & BIT(8); + pr->bypass_ibc_sc = r[16] & BIT(7); +} + +static void rtl839x_pie_rule_dump_raw(u32 r[]) +{ + pr_debug("Raw IACL table entry:\n"); + pr_debug("Match : %08x %08x %08x %08x %08x %08x\n", r[0], r[1], r[2], r[3], r[4], r[5]); + pr_debug("Fixed : %06x\n", r[6] >> 8); + pr_debug("Match M: %08x %08x %08x %08x %08x %08x\n", + (r[6] << 24) | (r[7] >> 8), (r[7] << 24) | (r[8] >> 8), (r[8] << 24) | (r[9] >> 8), + (r[9] << 24) | (r[10] >> 8), (r[10] << 24) | (r[11] >> 8), + (r[11] << 24) | (r[12] >> 8)); + pr_debug("R[13]: %08x\n", r[13]); + pr_debug("Fixed M: %06x\n", ((r[12] << 16) | (r[13] >> 16)) & 0xffffff); + pr_debug("Valid / not / and1 / and2 : %1x\n", (r[13] >> 12) & 0xf); + pr_debug("r 13-16: %08x %08x %08x %08x\n", r[13], r[14], r[15], r[16]); +} + +void rtl839x_pie_rule_dump(struct pie_rule *pr) +{ + pr_debug("Drop: %d, fwd: %d, ovid: %d, ivid: %d, flt: %d, log: %d, rmk: %d, meter: %d tagst: %d, mir: %d, nopri: %d, cpupri: %d, otpid: %d, itpid: %d, shape: %d\n", + pr->drop, pr->fwd_sel, pr->ovid_sel, pr->ivid_sel, pr->flt_sel, pr->log_sel, pr->rmk_sel, pr->log_sel, pr->tagst_sel, pr->mir_sel, pr->nopri_sel, + pr->cpupri_sel, pr->otpid_sel, pr->itpid_sel, pr->shaper_sel); + if (pr->fwd_sel) + pr_debug("FWD: %08x\n", pr->fwd_data); + pr_debug("TID: %x, %x\n", pr->tid, pr->tid_m); +} + +int rtl839x_pie_rule_read(struct rtl838x_switch_priv *priv, int idx, struct pie_rule *pr) +{ + int tbl = otto_table_acquire(RTL8390_TBL_IACL); + u32 r[17]; + int block = idx / PIE_BLOCK_SIZE; + u32 t_select = sw_r32(RTL839X_ACL_BLK_TMPLTE_CTRL(block)); + + memset(pr, 0, sizeof(*pr)); + __otto_table_read(tbl, idx, &r); + + otto_table_release(tbl); + + rtl839x_read_pie_fixed_fields(r, pr); + if (!pr->valid) + return 0; + + pr_debug("%s: template_selectors %08x, tid: %d\n", __func__, t_select, pr->tid); + rtl839x_pie_rule_dump_raw(r); + + rtl839x_read_pie_templated(r, pr, rtl839x_fixed_templates[(t_select >> (pr->tid * 3)) & 0x7]); + + rtl839x_read_pie_action(r, pr); + + return 0; +} + +int rtl839x_pie_rule_write(struct rtl838x_switch_priv *priv, int idx, struct pie_rule *pr) +{ + int tbl = otto_table_acquire(RTL8390_TBL_IACL); + u32 r[17]; + int block = idx / PIE_BLOCK_SIZE; + u32 t_select = sw_r32(RTL839X_ACL_BLK_TMPLTE_CTRL(block)); + + pr_debug("%s: %d, t_select: %08x\n", __func__, idx, t_select); + + for (int i = 0; i < 17; i++) + r[i] = 0; + + if (!pr->valid) { + __otto_table_write(tbl, idx, &r); + otto_table_release(tbl); + return 0; + } + rtl839x_write_pie_fixed_fields(r, pr); + + pr_debug("%s: template %d\n", __func__, (t_select >> (pr->tid * 3)) & 0x7); + rtl839x_write_pie_templated(r, pr, rtl839x_fixed_templates[(t_select >> (pr->tid * 3)) & 0x7]); + + rtl839x_write_pie_action(r, pr); + +/* rtl839x_pie_rule_dump_raw(r); */ + + __otto_table_write(tbl, idx, &r); + otto_table_release(tbl); + + return 0; +} + +static bool rtl839x_pie_templ_has(int t, enum rtl839x_template_field_id field_type) +{ + for (int i = 0; i < N_FIXED_FIELDS; i++) { + enum rtl839x_template_field_id ft = rtl839x_fixed_templates[t][i]; + + if (field_type == ft) + return true; + } + + return false; +} + +static int rtl839x_pie_verify_template(struct rtl838x_switch_priv *priv, + struct pie_rule *pr, int t, int block) +{ + int i; + + if (!pr->is_ipv6 && pr->sip_m && !rtl839x_pie_templ_has(t, RTL839X_TEMPLATE_FIELD_SIP0)) + return -1; + + if (!pr->is_ipv6 && pr->dip_m && !rtl839x_pie_templ_has(t, RTL839X_TEMPLATE_FIELD_DIP0)) + return -1; + + if (pr->is_ipv6) { + if ((pr->sip6_m.s6_addr32[0] || + pr->sip6_m.s6_addr32[1] || + pr->sip6_m.s6_addr32[2] || + pr->sip6_m.s6_addr32[3]) && + !rtl839x_pie_templ_has(t, RTL839X_TEMPLATE_FIELD_SIP2)) + return -1; + if ((pr->dip6_m.s6_addr32[0] || + pr->dip6_m.s6_addr32[1] || + pr->dip6_m.s6_addr32[2] || + pr->dip6_m.s6_addr32[3]) && + !rtl839x_pie_templ_has(t, RTL839X_TEMPLATE_FIELD_DIP2)) + return -1; + } + + if (ether_addr_to_u64(pr->smac_m) && !rtl839x_pie_templ_has(t, RTL839X_TEMPLATE_FIELD_SMAC0)) + return -1; + + if (ether_addr_to_u64(pr->dmac_m) && !rtl839x_pie_templ_has(t, RTL839X_TEMPLATE_FIELD_DMAC0)) + return -1; + + if (pr->itag_m && !rtl839x_pie_templ_has(t, RTL839X_TEMPLATE_FIELD_ITAG)) + return -1; + + if (pr->sport_m && !rtl839x_pie_templ_has(t, RTL839X_TEMPLATE_FIELD_L4_SPORT)) + return -1; + + if (pr->dport_m && !rtl839x_pie_templ_has(t, RTL839X_TEMPLATE_FIELD_L4_DPORT)) + return -1; + + /* TODO: Check more */ + + i = find_first_zero_bit(&priv->pie_use_bm[block * 4], PIE_BLOCK_SIZE); + + if (i >= PIE_BLOCK_SIZE) + return -1; + + return i + PIE_BLOCK_SIZE * block; +} + +int rtl839x_pie_rule_add(struct rtl838x_switch_priv *priv, struct pie_rule *pr) +{ + int idx, block, j, t; + int min_block = 0; + int max_block = priv->r->n_pie_blocks / 2; + + if (pr->is_egress) { + min_block = max_block; + max_block = priv->r->n_pie_blocks; + } + + mutex_lock(&priv->pie_mutex); + + for (block = min_block; block < max_block; block++) { + for (j = 0; j < 2; j++) { + t = (sw_r32(RTL839X_ACL_BLK_TMPLTE_CTRL(block)) >> (j * 3)) & 0x7; + idx = rtl839x_pie_verify_template(priv, pr, t, block); + if (idx >= 0) + break; + } + if (j < 2) + break; + } + + if (block >= max_block) { + mutex_unlock(&priv->pie_mutex); + return -EOPNOTSUPP; + } + + set_bit(idx, priv->pie_use_bm); + + pr->valid = true; + pr->tid = j; /* Mapped to template number */ + pr->tid_m = 0x3; + pr->id = idx; + + rtl839x_pie_lookup_enable(priv, idx); + rtl839x_pie_rule_write(priv, idx, pr); + + mutex_unlock(&priv->pie_mutex); + + return 0; +} + +void rtl839x_pie_rule_rm(struct rtl838x_switch_priv *priv, struct pie_rule *pr) +{ + int idx = pr->id; + + rtl839x_pie_rule_del(priv, idx, idx); + clear_bit(idx, priv->pie_use_bm); +} + +void rtl839x_pie_init(struct rtl838x_switch_priv *priv) +{ + u32 template_selectors; + + mutex_init(&priv->pie_mutex); + + /* Power on all PIE blocks */ + for (int i = 0; i < priv->r->n_pie_blocks; i++) + sw_w32_mask(0, BIT(i), RTL839X_PS_ACL_PWR_CTRL); + + /* Set ingress and egress ACL blocks to 50/50: first Egress block is 9 */ + sw_w32_mask(0x1f, 9, RTL839X_ACL_CTRL); /* Writes 9 to cutline field */ + + /* Include IPG in metering */ + sw_w32(1, RTL839X_METER_GLB_CTRL); + + /* Delete all present rules */ + rtl839x_pie_rule_del(priv, 0, priv->r->n_pie_blocks * PIE_BLOCK_SIZE - 1); + + /* Enable predefined templates 0, 1 for blocks 0-2 */ + template_selectors = 0 | (1 << 3); + for (int i = 0; i < 3; i++) + sw_w32(template_selectors, RTL839X_ACL_BLK_TMPLTE_CTRL(i)); + + /* Enable predefined templates 2, 3 for blocks 3-5 */ + template_selectors = 2 | (3 << 3); + for (int i = 3; i < 6; i++) + sw_w32(template_selectors, RTL839X_ACL_BLK_TMPLTE_CTRL(i)); + + /* Enable predefined templates 1, 4 for blocks 6-8 */ + template_selectors = 2 | (3 << 3); + for (int i = 6; i < 9; i++) + sw_w32(template_selectors, RTL839X_ACL_BLK_TMPLTE_CTRL(i)); + + /* Enable predefined templates 0, 1 for blocks 9-11 */ + template_selectors = 0 | (1 << 3); + for (int i = 9; i < 12; i++) + sw_w32(template_selectors, RTL839X_ACL_BLK_TMPLTE_CTRL(i)); + + /* Enable predefined templates 2, 3 for blocks 12-14 */ + template_selectors = 2 | (3 << 3); + for (int i = 12; i < 15; i++) + sw_w32(template_selectors, RTL839X_ACL_BLK_TMPLTE_CTRL(i)); + + /* Enable predefined templates 1, 4 for blocks 15-17 */ + template_selectors = 2 | (3 << 3); + for (int i = 15; i < 18; i++) + sw_w32(template_selectors, RTL839X_ACL_BLK_TMPLTE_CTRL(i)); +} + +/* RTL930X */ + +/* Definition of the RTL930X-specific template field IDs as used in the PIE */ +enum rtl930x_template_field_id { + RTL930X_TEMPLATE_FIELD_SPM0 = 0, /* Source portmask ports 0-15 */ + RTL930X_TEMPLATE_FIELD_SPM1 = 1, /* Source portmask ports 16-31 */ + RTL930X_TEMPLATE_FIELD_DMAC0 = 2, /* Destination MAC [15:0] */ + RTL930X_TEMPLATE_FIELD_DMAC1 = 3, /* Destination MAC [31:16] */ + RTL930X_TEMPLATE_FIELD_DMAC2 = 4, /* Destination MAC [47:32] */ + RTL930X_TEMPLATE_FIELD_SMAC0 = 5, /* Source MAC [15:0] */ + RTL930X_TEMPLATE_FIELD_SMAC1 = 6, /* Source MAC [31:16] */ + RTL930X_TEMPLATE_FIELD_SMAC2 = 7, /* Source MAC [47:32] */ + RTL930X_TEMPLATE_FIELD_ETHERTYPE = 8, /* Ethernet frame type field */ + RTL930X_TEMPLATE_FIELD_OTAG = 9, + RTL930X_TEMPLATE_FIELD_ITAG = 10, + RTL930X_TEMPLATE_FIELD_SIP0 = 11, + RTL930X_TEMPLATE_FIELD_SIP1 = 12, + RTL930X_TEMPLATE_FIELD_DIP0 = 13, + RTL930X_TEMPLATE_FIELD_DIP1 = 14, + RTL930X_TEMPLATE_FIELD_IP_TOS_PROTO = 15, + RTL930X_TEMPLATE_FIELD_L4_SPORT = 16, + RTL930X_TEMPLATE_FIELD_L4_DPORT = 17, + RTL930X_TEMPLATE_FIELD_L34_HEADER = 18, + RTL930X_TEMPLATE_FIELD_TCP_INFO = 19, + RTL930X_TEMPLATE_FIELD_FIELD_SELECTOR_VALID = 20, + RTL930X_TEMPLATE_FIELD_FIELD_SELECTOR_0 = 21, + RTL930X_TEMPLATE_FIELD_FIELD_SELECTOR_1 = 22, + RTL930X_TEMPLATE_FIELD_FIELD_SELECTOR_2 = 23, + RTL930X_TEMPLATE_FIELD_FIELD_SELECTOR_3 = 24, + RTL930X_TEMPLATE_FIELD_FIELD_SELECTOR_4 = 25, + RTL930X_TEMPLATE_FIELD_FIELD_SELECTOR_5 = 26, + RTL930X_TEMPLATE_FIELD_SIP2 = 27, + RTL930X_TEMPLATE_FIELD_SIP3 = 28, + RTL930X_TEMPLATE_FIELD_SIP4 = 29, + RTL930X_TEMPLATE_FIELD_SIP5 = 30, + RTL930X_TEMPLATE_FIELD_SIP6 = 31, + RTL930X_TEMPLATE_FIELD_SIP7 = 32, + RTL930X_TEMPLATE_FIELD_DIP2 = 33, + RTL930X_TEMPLATE_FIELD_DIP3 = 34, + RTL930X_TEMPLATE_FIELD_DIP4 = 35, + RTL930X_TEMPLATE_FIELD_DIP5 = 36, + RTL930X_TEMPLATE_FIELD_DIP6 = 37, + RTL930X_TEMPLATE_FIELD_DIP7 = 38, + RTL930X_TEMPLATE_FIELD_PKT_INFO = 39, + RTL930X_TEMPLATE_FIELD_FLOW_LABEL = 40, + RTL930X_TEMPLATE_FIELD_DSAP_SSAP = 41, + RTL930X_TEMPLATE_FIELD_SNAP_OUI = 42, + RTL930X_TEMPLATE_FIELD_FWD_VID = 43, + RTL930X_TEMPLATE_FIELD_RANGE_CHK = 44, + RTL930X_TEMPLATE_FIELD_VLAN_GMSK = 45, /* VLAN Group Mask/IP range check */ + RTL930X_TEMPLATE_FIELD_DLP = 46, + RTL930X_TEMPLATE_FIELD_META_DATA = 47, + RTL930X_TEMPLATE_FIELD_SRC_FWD_VID = 48, + RTL930X_TEMPLATE_FIELD_SLP = 49, +}; + +/* The meaning of RTL930X_TEMPLATE_FIELD_VLAN depends on phase and the configuration in + * RTL930X_PIE_CTRL. We use always the same definition and map to the inner VLAN tag: + */ +#define RTL930X_TEMPLATE_FIELD_VLAN RTL930X_TEMPLATE_FIELD_ITAG + +/* Number of fixed templates predefined in the RTL9300 SoC */ +#define RTL930X_N_FIXED_TEMPLATES 5 +/* RTL9300 specific predefined templates */ +static enum rtl930x_template_field_id rtl930x_fixed_templates[RTL930X_N_FIXED_TEMPLATES][N_FIXED_FIELDS] = { + { + RTL930X_TEMPLATE_FIELD_DMAC0, RTL930X_TEMPLATE_FIELD_DMAC1, RTL930X_TEMPLATE_FIELD_DMAC2, + RTL930X_TEMPLATE_FIELD_SMAC0, RTL930X_TEMPLATE_FIELD_SMAC1, RTL930X_TEMPLATE_FIELD_SMAC2, + RTL930X_TEMPLATE_FIELD_VLAN, RTL930X_TEMPLATE_FIELD_IP_TOS_PROTO, RTL930X_TEMPLATE_FIELD_DSAP_SSAP, + RTL930X_TEMPLATE_FIELD_ETHERTYPE, RTL930X_TEMPLATE_FIELD_SPM0, RTL930X_TEMPLATE_FIELD_SPM1 + }, { + RTL930X_TEMPLATE_FIELD_SIP0, RTL930X_TEMPLATE_FIELD_SIP1, RTL930X_TEMPLATE_FIELD_DIP0, + RTL930X_TEMPLATE_FIELD_DIP1, RTL930X_TEMPLATE_FIELD_IP_TOS_PROTO, RTL930X_TEMPLATE_FIELD_TCP_INFO, + RTL930X_TEMPLATE_FIELD_L4_SPORT, RTL930X_TEMPLATE_FIELD_L4_DPORT, RTL930X_TEMPLATE_FIELD_VLAN, + RTL930X_TEMPLATE_FIELD_RANGE_CHK, RTL930X_TEMPLATE_FIELD_SPM0, RTL930X_TEMPLATE_FIELD_SPM1 + }, { + RTL930X_TEMPLATE_FIELD_DMAC0, RTL930X_TEMPLATE_FIELD_DMAC1, RTL930X_TEMPLATE_FIELD_DMAC2, + RTL930X_TEMPLATE_FIELD_VLAN, RTL930X_TEMPLATE_FIELD_ETHERTYPE, RTL930X_TEMPLATE_FIELD_IP_TOS_PROTO, + RTL930X_TEMPLATE_FIELD_SIP0, RTL930X_TEMPLATE_FIELD_SIP1, RTL930X_TEMPLATE_FIELD_DIP0, + RTL930X_TEMPLATE_FIELD_DIP1, RTL930X_TEMPLATE_FIELD_L4_SPORT, RTL930X_TEMPLATE_FIELD_L4_DPORT + }, { + RTL930X_TEMPLATE_FIELD_DIP0, RTL930X_TEMPLATE_FIELD_DIP1, RTL930X_TEMPLATE_FIELD_DIP2, + RTL930X_TEMPLATE_FIELD_DIP3, RTL930X_TEMPLATE_FIELD_DIP4, RTL930X_TEMPLATE_FIELD_DIP5, + RTL930X_TEMPLATE_FIELD_DIP6, RTL930X_TEMPLATE_FIELD_DIP7, RTL930X_TEMPLATE_FIELD_IP_TOS_PROTO, + RTL930X_TEMPLATE_FIELD_TCP_INFO, RTL930X_TEMPLATE_FIELD_L4_SPORT, RTL930X_TEMPLATE_FIELD_L4_DPORT + }, { + RTL930X_TEMPLATE_FIELD_SIP0, RTL930X_TEMPLATE_FIELD_SIP1, RTL930X_TEMPLATE_FIELD_SIP2, + RTL930X_TEMPLATE_FIELD_SIP3, RTL930X_TEMPLATE_FIELD_SIP4, RTL930X_TEMPLATE_FIELD_SIP5, + RTL930X_TEMPLATE_FIELD_SIP6, RTL930X_TEMPLATE_FIELD_SIP7, RTL930X_TEMPLATE_FIELD_VLAN, + RTL930X_TEMPLATE_FIELD_RANGE_CHK, RTL930X_TEMPLATE_FIELD_SPM1, RTL930X_TEMPLATE_FIELD_SPM1 + }, +}; + +static void rtl930x_pie_lookup_enable(struct rtl838x_switch_priv *priv, int index) +{ + int block = index / PIE_BLOCK_SIZE; + + sw_w32_mask(0, BIT(block), RTL930X_PIE_BLK_LOOKUP_CTRL); +} + +/* Reads the intermediate representation of the templated match-fields of the + * PIE rule in the pie_rule structure and fills in the raw data fields in the + * raw register space r[]. + * The register space configuration size is identical for the RTL8380/90 and RTL9300, + * however the RTL9310 has 2 more registers / fields and the physical field-ids are different + * on all SoCs + * On the RTL9300 the mask fields are not word-aligend! + */ +static void rtl930x_write_pie_templated(u32 r[], struct pie_rule *pr, enum rtl930x_template_field_id t[]) +{ + for (int i = 0; i < N_FIXED_FIELDS; i++) { + enum rtl930x_template_field_id field_type = t[i]; + u16 data = 0, data_m = 0; + + switch (field_type) { + case RTL930X_TEMPLATE_FIELD_SPM0: + data = pr->spm; + data_m = pr->spm_m; + break; + case RTL930X_TEMPLATE_FIELD_SPM1: + data = pr->spm >> 16; + data_m = pr->spm_m >> 16; + break; + case RTL930X_TEMPLATE_FIELD_OTAG: + data = pr->otag; + data_m = pr->otag_m; + break; + case RTL930X_TEMPLATE_FIELD_SMAC0: + data = pr->smac[4]; + data = (data << 8) | pr->smac[5]; + data_m = pr->smac_m[4]; + data_m = (data_m << 8) | pr->smac_m[5]; + break; + case RTL930X_TEMPLATE_FIELD_SMAC1: + data = pr->smac[2]; + data = (data << 8) | pr->smac[3]; + data_m = pr->smac_m[2]; + data_m = (data_m << 8) | pr->smac_m[3]; + break; + case RTL930X_TEMPLATE_FIELD_SMAC2: + data = pr->smac[0]; + data = (data << 8) | pr->smac[1]; + data_m = pr->smac_m[0]; + data_m = (data_m << 8) | pr->smac_m[1]; + break; + case RTL930X_TEMPLATE_FIELD_DMAC0: + data = pr->dmac[4]; + data = (data << 8) | pr->dmac[5]; + data_m = pr->dmac_m[4]; + data_m = (data_m << 8) | pr->dmac_m[5]; + break; + case RTL930X_TEMPLATE_FIELD_DMAC1: + data = pr->dmac[2]; + data = (data << 8) | pr->dmac[3]; + data_m = pr->dmac_m[2]; + data_m = (data_m << 8) | pr->dmac_m[3]; + break; + case RTL930X_TEMPLATE_FIELD_DMAC2: + data = pr->dmac[0]; + data = (data << 8) | pr->dmac[1]; + data_m = pr->dmac_m[0]; + data_m = (data_m << 8) | pr->dmac_m[1]; + break; + case RTL930X_TEMPLATE_FIELD_ETHERTYPE: + data = pr->ethertype; + data_m = pr->ethertype_m; + break; + case RTL930X_TEMPLATE_FIELD_ITAG: + data = pr->itag; + data_m = pr->itag_m; + break; + case RTL930X_TEMPLATE_FIELD_SIP0: + if (pr->is_ipv6) { + data = pr->sip6.s6_addr16[7]; + data_m = pr->sip6_m.s6_addr16[7]; + } else { + data = pr->sip; + data_m = pr->sip_m; + } + break; + case RTL930X_TEMPLATE_FIELD_SIP1: + if (pr->is_ipv6) { + data = pr->sip6.s6_addr16[6]; + data_m = pr->sip6_m.s6_addr16[6]; + } else { + data = pr->sip >> 16; + data_m = pr->sip_m >> 16; + } + break; + case RTL930X_TEMPLATE_FIELD_SIP2: + case RTL930X_TEMPLATE_FIELD_SIP3: + case RTL930X_TEMPLATE_FIELD_SIP4: + case RTL930X_TEMPLATE_FIELD_SIP5: + case RTL930X_TEMPLATE_FIELD_SIP6: + case RTL930X_TEMPLATE_FIELD_SIP7: + data = pr->sip6.s6_addr16[5 - (field_type - RTL930X_TEMPLATE_FIELD_SIP2)]; + data_m = pr->sip6_m.s6_addr16[5 - (field_type - RTL930X_TEMPLATE_FIELD_SIP2)]; + break; + case RTL930X_TEMPLATE_FIELD_DIP0: + if (pr->is_ipv6) { + data = pr->dip6.s6_addr16[7]; + data_m = pr->dip6_m.s6_addr16[7]; + } else { + data = pr->dip; + data_m = pr->dip_m; + } + break; + case RTL930X_TEMPLATE_FIELD_DIP1: + if (pr->is_ipv6) { + data = pr->dip6.s6_addr16[6]; + data_m = pr->dip6_m.s6_addr16[6]; + } else { + data = pr->dip >> 16; + data_m = pr->dip_m >> 16; + } + break; + case RTL930X_TEMPLATE_FIELD_DIP2: + case RTL930X_TEMPLATE_FIELD_DIP3: + case RTL930X_TEMPLATE_FIELD_DIP4: + case RTL930X_TEMPLATE_FIELD_DIP5: + case RTL930X_TEMPLATE_FIELD_DIP6: + case RTL930X_TEMPLATE_FIELD_DIP7: + data = pr->dip6.s6_addr16[5 - (field_type - RTL930X_TEMPLATE_FIELD_DIP2)]; + data_m = pr->dip6_m.s6_addr16[5 - (field_type - RTL930X_TEMPLATE_FIELD_DIP2)]; + break; + case RTL930X_TEMPLATE_FIELD_IP_TOS_PROTO: + data = pr->tos_proto; + data_m = pr->tos_proto_m; + break; + case RTL930X_TEMPLATE_FIELD_L4_SPORT: + data = pr->sport; + data_m = pr->sport_m; + break; + case RTL930X_TEMPLATE_FIELD_L4_DPORT: + data = pr->dport; + data_m = pr->dport_m; + break; + case RTL930X_TEMPLATE_FIELD_DSAP_SSAP: + data = pr->dsap_ssap; + data_m = pr->dsap_ssap_m; + break; + case RTL930X_TEMPLATE_FIELD_TCP_INFO: + data = pr->tcp_info; + data_m = pr->tcp_info_m; + break; + case RTL930X_TEMPLATE_FIELD_RANGE_CHK: + pr_debug("RTL930X_TEMPLATE_FIELD_RANGE_CHK: not configured\n"); + break; + default: + pr_debug("%s: unknown field %d\n", __func__, field_type); + } + + /* On the RTL9300, the mask fields are not word aligned! */ + if (!(i % 2)) { + r[5 - i / 2] = data; + r[12 - i / 2] |= ((u32)data_m << 8); + } else { + r[5 - i / 2] |= ((u32)data) << 16; + r[12 - i / 2] |= ((u32)data_m) << 24; + r[11 - i / 2] |= ((u32)data_m) >> 8; + } + } +} + +// Currently not used +// static void rtl930x_read_pie_fixed_fields(u32 r[], struct pie_rule *pr) +// { +// pr->stacking_port = r[6] & BIT(31); +// pr->spn = (r[6] >> 24) & 0x7f; +// pr->mgnt_vlan = r[6] & BIT(23); +// if (pr->phase == PHASE_IACL) +// pr->dmac_hit_sw = r[6] & BIT(22); +// else +// pr->content_too_deep = r[6] & BIT(22); +// pr->not_first_frag = r[6] & BIT(21); +// pr->frame_type_l4 = (r[6] >> 18) & 7; +// pr->frame_type = (r[6] >> 16) & 3; +// pr->otag_fmt = (r[6] >> 15) & 1; +// pr->itag_fmt = (r[6] >> 14) & 1; +// pr->otag_exist = (r[6] >> 13) & 1; +// pr->itag_exist = (r[6] >> 12) & 1; +// pr->frame_type_l2 = (r[6] >> 10) & 3; +// pr->igr_normal_port = (r[6] >> 9) & 1; +// pr->tid = (r[6] >> 8) & 1; + +// pr->stacking_port_m = r[12] & BIT(7); +// pr->spn_m = r[12] & 0x7f; +// pr->mgnt_vlan_m = r[13] & BIT(31); +// if (pr->phase == PHASE_IACL) +// pr->dmac_hit_sw_m = r[13] & BIT(30); +// else +// pr->content_too_deep_m = r[13] & BIT(30); +// pr->not_first_frag_m = r[13] & BIT(29); +// pr->frame_type_l4_m = (r[13] >> 26) & 7; +// pr->frame_type_m = (r[13] >> 24) & 3; +// pr->otag_fmt_m = r[13] & BIT(23); +// pr->itag_fmt_m = r[13] & BIT(22); +// pr->otag_exist_m = r[13] & BIT(21); +// pr->itag_exist_m = r[13] & BIT (20); +// pr->frame_type_l2_m = (r[13] >> 18) & 3; +// pr->igr_normal_port_m = r[13] & BIT(17); +// pr->tid_m = (r[13] >> 16) & 1; + +// pr->valid = r[13] & BIT(15); +// pr->cond_not = r[13] & BIT(14); +// pr->cond_and1 = r[13] & BIT(13); +// pr->cond_and2 = r[13] & BIT(12); +// } + +static void rtl930x_write_pie_fixed_fields(u32 r[], struct pie_rule *pr) +{ + r[6] = pr->stacking_port ? BIT(31) : 0; + r[6] |= ((u32)(pr->spn & 0x7f)) << 24; + r[6] |= pr->mgnt_vlan ? BIT(23) : 0; + if (pr->phase == PHASE_IACL) + r[6] |= pr->dmac_hit_sw ? BIT(22) : 0; + else + r[6] |= pr->content_too_deep ? BIT(22) : 0; + r[6] |= pr->not_first_frag ? BIT(21) : 0; + r[6] |= ((u32)(pr->frame_type_l4 & 0x7)) << 18; + r[6] |= ((u32)(pr->frame_type & 0x3)) << 16; + r[6] |= pr->otag_fmt ? BIT(15) : 0; + r[6] |= pr->itag_fmt ? BIT(14) : 0; + r[6] |= pr->otag_exist ? BIT(13) : 0; + r[6] |= pr->itag_exist ? BIT(12) : 0; + r[6] |= ((u32)(pr->frame_type_l2 & 0x3)) << 10; + r[6] |= pr->igr_normal_port ? BIT(9) : 0; + r[6] |= ((u32)(pr->tid & 0x1)) << 8; + + r[12] |= pr->stacking_port_m ? BIT(7) : 0; + r[12] |= (u32)(pr->spn_m & 0x7f); + r[13] |= pr->mgnt_vlan_m ? BIT(31) : 0; + if (pr->phase == PHASE_IACL) + r[13] |= pr->dmac_hit_sw_m ? BIT(30) : 0; + else + r[13] |= pr->content_too_deep_m ? BIT(30) : 0; + r[13] |= pr->not_first_frag_m ? BIT(29) : 0; + r[13] |= ((u32)(pr->frame_type_l4_m & 0x7)) << 26; + r[13] |= ((u32)(pr->frame_type_m & 0x3)) << 24; + r[13] |= pr->otag_fmt_m ? BIT(23) : 0; + r[13] |= pr->itag_fmt_m ? BIT(22) : 0; + r[13] |= pr->otag_exist_m ? BIT(21) : 0; + r[13] |= pr->itag_exist_m ? BIT(20) : 0; + r[13] |= ((u32)(pr->frame_type_l2_m & 0x3)) << 18; + r[13] |= pr->igr_normal_port_m ? BIT(17) : 0; + r[13] |= ((u32)(pr->tid_m & 0x1)) << 16; + + r[13] |= pr->valid ? BIT(15) : 0; + r[13] |= pr->cond_not ? BIT(14) : 0; + r[13] |= pr->cond_and1 ? BIT(13) : 0; + r[13] |= pr->cond_and2 ? BIT(12) : 0; +} + +static void rtl930x_write_pie_action(u32 r[], struct pie_rule *pr) +{ + /* Either drop or forward */ + if (pr->drop) { + r[14] |= BIT(24) | BIT(25) | BIT(26); /* Do Green, Yellow and Red drops */ + /* Actually DROP, not PERMIT in Green / Yellow / Red */ + r[14] |= BIT(23) | BIT(22) | BIT(20); + } else { + r[14] |= pr->fwd_sel ? BIT(27) : 0; + r[14] |= pr->fwd_act << 18; + r[14] |= BIT(14); /* We overwrite any drop */ + } + if (pr->phase == PHASE_VACL) + r[14] |= pr->fwd_sa_lrn ? BIT(15) : 0; + r[13] |= pr->bypass_sel ? BIT(5) : 0; + r[13] |= pr->nopri_sel ? BIT(4) : 0; + r[13] |= pr->tagst_sel ? BIT(3) : 0; + r[13] |= pr->ovid_sel ? BIT(1) : 0; + r[14] |= pr->ivid_sel ? BIT(31) : 0; + r[14] |= pr->meter_sel ? BIT(30) : 0; + r[14] |= pr->mir_sel ? BIT(29) : 0; + r[14] |= pr->log_sel ? BIT(28) : 0; + + r[14] |= ((u32)(pr->fwd_data & 0x3fff)) << 3; + r[15] |= pr->log_octets ? BIT(31) : 0; + r[15] |= (u32)(pr->meter_data) << 23; + + r[15] |= ((u32)(pr->ivid_act) & 0x3) << 21; + r[15] |= ((u32)(pr->ivid_data) & 0xfff) << 9; + r[16] |= ((u32)(pr->ovid_act) & 0x3) << 30; + r[16] |= ((u32)(pr->ovid_data) & 0xfff) << 16; + r[16] |= (pr->mir_data & 0x3) << 6; + r[17] |= ((u32)(pr->tagst_data) & 0xf) << 28; + r[17] |= ((u32)(pr->nopri_data) & 0x7) << 25; + r[17] |= pr->bypass_ibc_sc ? BIT(16) : 0; +} + +void rtl930x_pie_rule_dump_raw(u32 r[]) +{ + pr_debug("Raw IACL table entry:\n"); + pr_debug("r 0 - 7: %08x %08x %08x %08x %08x %08x %08x %08x\n", + r[0], r[1], r[2], r[3], r[4], r[5], r[6], r[7]); + pr_debug("r 8 - 15: %08x %08x %08x %08x %08x %08x %08x %08x\n", + r[8], r[9], r[10], r[11], r[12], r[13], r[14], r[15]); + pr_debug("r 16 - 18: %08x %08x %08x\n", r[16], r[17], r[18]); + pr_debug("Match : %08x %08x %08x %08x %08x %08x\n", r[0], r[1], r[2], r[3], r[4], r[5]); + pr_debug("Fixed : %06x\n", r[6] >> 8); + pr_debug("Match M: %08x %08x %08x %08x %08x %08x\n", + (r[6] << 24) | (r[7] >> 8), (r[7] << 24) | (r[8] >> 8), (r[8] << 24) | (r[9] >> 8), + (r[9] << 24) | (r[10] >> 8), (r[10] << 24) | (r[11] >> 8), + (r[11] << 24) | (r[12] >> 8)); + pr_debug("R[13]: %08x\n", r[13]); + pr_debug("Fixed M: %06x\n", ((r[12] << 16) | (r[13] >> 16)) & 0xffffff); + pr_debug("Valid / not / and1 / and2 : %1x\n", (r[13] >> 12) & 0xf); + pr_debug("r 13-16: %08x %08x %08x %08x\n", r[13], r[14], r[15], r[16]); +} + +int rtl930x_pie_rule_write(struct rtl838x_switch_priv *priv, int idx, struct pie_rule *pr) +{ + int tbl = otto_table_acquire(RTL9300_TBL_IACL); + u32 r[19]; + int block = idx / PIE_BLOCK_SIZE; + u32 t_select = sw_r32(RTL930X_PIE_BLK_TMPLTE_CTRL(block)); + + pr_debug("%s: %d, t_select: %08x\n", __func__, idx, t_select); + + for (int i = 0; i < 19; i++) + r[i] = 0; + + if (!pr->valid) { + __otto_table_write(tbl, idx, &r); + otto_table_release(tbl); + return 0; + } + rtl930x_write_pie_fixed_fields(r, pr); + + pr_debug("%s: template %d\n", __func__, (t_select >> (pr->tid * 4)) & 0xf); + rtl930x_write_pie_templated(r, pr, rtl930x_fixed_templates[(t_select >> (pr->tid * 4)) & 0xf]); + + rtl930x_write_pie_action(r, pr); + +/* rtl930x_pie_rule_dump_raw(r); */ + + __otto_table_write(tbl, idx, &r); + otto_table_release(tbl); + + return 0; +} + +static bool rtl930x_pie_templ_has(int t, enum rtl930x_template_field_id field_type) +{ + for (int i = 0; i < N_FIXED_FIELDS; i++) { + enum rtl930x_template_field_id ft = rtl930x_fixed_templates[t][i]; + + if (field_type == ft) + return true; + } + + return false; +} + +/* Verify that the rule pr is compatible with a given template t in block + * Note that this function is SoC specific since the values of e.g. RTL930X_TEMPLATE_FIELD_SIP0 + * depend on the SoC + */ +static int rtl930x_pie_verify_template(struct rtl838x_switch_priv *priv, + struct pie_rule *pr, int t, int block) +{ + int i; + + if (!pr->is_ipv6 && pr->sip_m && !rtl930x_pie_templ_has(t, RTL930X_TEMPLATE_FIELD_SIP0)) + return -1; + + if (!pr->is_ipv6 && pr->dip_m && !rtl930x_pie_templ_has(t, RTL930X_TEMPLATE_FIELD_DIP0)) + return -1; + + if (pr->is_ipv6) { + if ((pr->sip6_m.s6_addr32[0] || + pr->sip6_m.s6_addr32[1] || + pr->sip6_m.s6_addr32[2] || + pr->sip6_m.s6_addr32[3]) && + !rtl930x_pie_templ_has(t, RTL930X_TEMPLATE_FIELD_SIP2)) + return -1; + if ((pr->dip6_m.s6_addr32[0] || + pr->dip6_m.s6_addr32[1] || + pr->dip6_m.s6_addr32[2] || + pr->dip6_m.s6_addr32[3]) && + !rtl930x_pie_templ_has(t, RTL930X_TEMPLATE_FIELD_DIP2)) + return -1; + } + + if (ether_addr_to_u64(pr->smac_m) && !rtl930x_pie_templ_has(t, RTL930X_TEMPLATE_FIELD_SMAC0)) + return -1; + + if (ether_addr_to_u64(pr->dmac_m) && !rtl930x_pie_templ_has(t, RTL930X_TEMPLATE_FIELD_DMAC0)) + return -1; + + if (pr->ethertype_m && !rtl930x_pie_templ_has(t, RTL930X_TEMPLATE_FIELD_ETHERTYPE)) + return -1; + + if (pr->itag_m && !rtl930x_pie_templ_has(t, RTL930X_TEMPLATE_FIELD_VLAN)) + return -1; + + if (pr->sport_m && !rtl930x_pie_templ_has(t, RTL930X_TEMPLATE_FIELD_L4_SPORT)) + return -1; + + if (pr->dport_m && !rtl930x_pie_templ_has(t, RTL930X_TEMPLATE_FIELD_L4_DPORT)) + return -1; + + /* TODO: Check more */ + + i = find_first_zero_bit(&priv->pie_use_bm[block * 4], PIE_BLOCK_SIZE); + + if (i >= PIE_BLOCK_SIZE) + return -1; + + return i + PIE_BLOCK_SIZE * block; +} + +int rtl930x_pie_rule_add(struct rtl838x_switch_priv *priv, struct pie_rule *pr) +{ + int idx, block, j, t; + int min_block = 0; + int max_block = priv->r->n_pie_blocks / 2; + + if (pr->is_egress) { + min_block = max_block; + max_block = priv->r->n_pie_blocks; + } + pr_debug("In %s\n", __func__); + + mutex_lock(&priv->pie_mutex); + + for (block = min_block; block < max_block; block++) { + for (j = 0; j < 2; j++) { + t = (sw_r32(RTL930X_PIE_BLK_TMPLTE_CTRL(block)) >> (j * 4)) & 0xf; + pr_debug("Testing block %d, template %d, template id %d\n", block, j, t); + pr_debug("%s: %08x\n", + __func__, sw_r32(RTL930X_PIE_BLK_TMPLTE_CTRL(block))); + idx = rtl930x_pie_verify_template(priv, pr, t, block); + if (idx >= 0) + break; + } + if (j < 2) + break; + } + + if (block >= max_block) { + mutex_unlock(&priv->pie_mutex); + return -EOPNOTSUPP; + } + + pr_debug("Using block: %d, index %d, template-id %d\n", block, idx, j); + set_bit(idx, priv->pie_use_bm); + + pr->valid = true; + pr->tid = j; /* Mapped to template number */ + pr->tid_m = 0x1; + pr->id = idx; + + rtl930x_pie_lookup_enable(priv, idx); + rtl930x_pie_rule_write(priv, idx, pr); + + mutex_unlock(&priv->pie_mutex); + return 0; +} + +/* Delete a range of Packet Inspection Engine rules */ +static int rtl930x_pie_rule_del(struct rtl838x_switch_priv *priv, int index_from, int index_to) +{ + u32 v = (index_from << 1) | (index_to << 12) | BIT(0); + + pr_debug("%s: from %d to %d\n", __func__, index_from, index_to); + mutex_lock(&priv->reg_mutex); + + /* Write from-to and execute bit into control register */ + sw_w32(v, RTL930X_PIE_CLR_CTRL); + + /* Wait until command has completed */ + do { + } while (sw_r32(RTL930X_PIE_CLR_CTRL) & BIT(0)); + + mutex_unlock(&priv->reg_mutex); + return 0; +} + +void rtl930x_pie_rule_rm(struct rtl838x_switch_priv *priv, struct pie_rule *pr) +{ + int idx = pr->id; + + rtl930x_pie_rule_del(priv, idx, idx); + clear_bit(idx, priv->pie_use_bm); +} + +void rtl930x_pie_init(struct rtl838x_switch_priv *priv) +{ + u32 template_selectors; + + mutex_init(&priv->pie_mutex); + + pr_debug("%s\n", __func__); + /* Enable ACL lookup on all ports, including CPU_PORT */ + for (int i = 0; i <= priv->r->cpu_port; i++) + sw_w32(1, RTL930X_ACL_PORT_LOOKUP_CTRL(i)); + + /* Include IPG in metering */ + sw_w32_mask(0, 1, RTL930X_METER_GLB_CTRL); + + /* Delete all present rules, block size is 128 on all SoC families */ + rtl930x_pie_rule_del(priv, 0, priv->r->n_pie_blocks * 128 - 1); + + /* Assign blocks 0-7 to VACL phase (bit = 0), blocks 8-15 to IACL (bit = 1) */ + sw_w32(0xff00, RTL930X_PIE_BLK_PHASE_CTRL); + + /* Enable predefined templates 0, 1 for first quarter of all blocks */ + template_selectors = 0 | (1 << 4); + for (int i = 0; i < priv->r->n_pie_blocks / 4; i++) + sw_w32(template_selectors, RTL930X_PIE_BLK_TMPLTE_CTRL(i)); + + /* Enable predefined templates 2, 3 for second quarter of all blocks */ + template_selectors = 2 | (3 << 4); + for (int i = priv->r->n_pie_blocks / 4; i < priv->r->n_pie_blocks / 2; i++) + sw_w32(template_selectors, RTL930X_PIE_BLK_TMPLTE_CTRL(i)); + + /* Enable predefined templates 0, 1 for third half of all blocks */ + template_selectors = 0 | (1 << 4); + for (int i = priv->r->n_pie_blocks / 2; i < priv->r->n_pie_blocks * 3 / 4; i++) + sw_w32(template_selectors, RTL930X_PIE_BLK_TMPLTE_CTRL(i)); + + /* Enable predefined templates 2, 3 for fourth quater of all blocks */ + template_selectors = 2 | (3 << 4); + for (int i = priv->r->n_pie_blocks * 3 / 4; i < priv->r->n_pie_blocks; i++) + sw_w32(template_selectors, RTL930X_PIE_BLK_TMPLTE_CTRL(i)); +} + +/* RTL931X */ + +/* Definition of the RTL931X-specific template field IDs as used in the PIE */ +enum rtl931x_template_field_id { + RTL931X_TEMPLATE_FIELD_SPM0 = 1, + RTL931X_TEMPLATE_FIELD_SPM1 = 2, + RTL931X_TEMPLATE_FIELD_SPM2 = 3, + RTL931X_TEMPLATE_FIELD_SPM3 = 4, + RTL931X_TEMPLATE_FIELD_DMAC0 = 9, + RTL931X_TEMPLATE_FIELD_DMAC1 = 10, + RTL931X_TEMPLATE_FIELD_DMAC2 = 11, + RTL931X_TEMPLATE_FIELD_SMAC0 = 12, + RTL931X_TEMPLATE_FIELD_SMAC1 = 13, + RTL931X_TEMPLATE_FIELD_SMAC2 = 14, + RTL931X_TEMPLATE_FIELD_ETHERTYPE = 15, + RTL931X_TEMPLATE_FIELD_OTAG = 16, + RTL931X_TEMPLATE_FIELD_ITAG = 17, + RTL931X_TEMPLATE_FIELD_SIP0 = 18, + RTL931X_TEMPLATE_FIELD_SIP1 = 19, + RTL931X_TEMPLATE_FIELD_DIP0 = 20, + RTL931X_TEMPLATE_FIELD_DIP1 = 21, + RTL931X_TEMPLATE_FIELD_IP_TOS_PROTO = 22, + RTL931X_TEMPLATE_FIELD_L4_SPORT = 23, + RTL931X_TEMPLATE_FIELD_L4_DPORT = 24, + RTL931X_TEMPLATE_FIELD_L34_HEADER = 25, + RTL931X_TEMPLATE_FIELD_TCP_INFO = 26, + RTL931X_TEMPLATE_FIELD_SIP2 = 34, + RTL931X_TEMPLATE_FIELD_SIP3 = 35, + RTL931X_TEMPLATE_FIELD_SIP4 = 36, + RTL931X_TEMPLATE_FIELD_SIP5 = 37, + RTL931X_TEMPLATE_FIELD_SIP6 = 38, + RTL931X_TEMPLATE_FIELD_SIP7 = 39, + RTL931X_TEMPLATE_FIELD_DIP2 = 42, + RTL931X_TEMPLATE_FIELD_DIP3 = 43, + RTL931X_TEMPLATE_FIELD_DIP4 = 44, + RTL931X_TEMPLATE_FIELD_DIP5 = 45, + RTL931X_TEMPLATE_FIELD_DIP6 = 46, + RTL931X_TEMPLATE_FIELD_DIP7 = 47, + RTL931X_TEMPLATE_FIELD_FLOW_LABEL = 49, + RTL931X_TEMPLATE_FIELD_DSAP_SSAP = 50, + RTL931X_TEMPLATE_FIELD_FWD_VID = 52, + RTL931X_TEMPLATE_FIELD_RANGE_CHK = 53, + RTL931X_TEMPLATE_FIELD_SLP = 55, + RTL931X_TEMPLATE_FIELD_DLP = 56, + RTL931X_TEMPLATE_FIELD_META_DATA = 57, + RTL931X_TEMPLATE_FIELD_FIRST_MPLS1 = 60, + RTL931X_TEMPLATE_FIELD_FIRST_MPLS2 = 61, + RTL931X_TEMPLATE_FIELD_DPM3 = 8, +}; + +/* The meaning of RTL931X_TEMPLATE_FIELD_VLAN depends on phase and the configuration in + * RTL931X_PIE_CTRL. We use always the same definition and map to the inner VLAN tag: + */ +#define RTL931X_TEMPLATE_FIELD_VLAN RTL931X_TEMPLATE_FIELD_ITAG + +/* Number of fixed templates predefined in the RTL9300 SoC */ +#define RTL931X_N_FIXED_TEMPLATES 5 +/* RTL931x specific predefined templates */ +static enum rtl931x_template_field_id rtl931x_fixed_templates[RTL931X_N_FIXED_TEMPLATES][N_FIXED_FIELDS_RTL931X] = { + { + RTL931X_TEMPLATE_FIELD_DMAC0, RTL931X_TEMPLATE_FIELD_DMAC1, RTL931X_TEMPLATE_FIELD_DMAC2, + RTL931X_TEMPLATE_FIELD_SMAC0, RTL931X_TEMPLATE_FIELD_SMAC1, RTL931X_TEMPLATE_FIELD_SMAC2, + RTL931X_TEMPLATE_FIELD_VLAN, RTL931X_TEMPLATE_FIELD_IP_TOS_PROTO, RTL931X_TEMPLATE_FIELD_DSAP_SSAP, + RTL931X_TEMPLATE_FIELD_ETHERTYPE, RTL931X_TEMPLATE_FIELD_SPM0, RTL931X_TEMPLATE_FIELD_SPM1, + RTL931X_TEMPLATE_FIELD_SPM2, RTL931X_TEMPLATE_FIELD_SPM3 + }, { + RTL931X_TEMPLATE_FIELD_SIP0, RTL931X_TEMPLATE_FIELD_SIP1, RTL931X_TEMPLATE_FIELD_DIP0, + RTL931X_TEMPLATE_FIELD_DIP1, RTL931X_TEMPLATE_FIELD_IP_TOS_PROTO, RTL931X_TEMPLATE_FIELD_TCP_INFO, + RTL931X_TEMPLATE_FIELD_L4_SPORT, RTL931X_TEMPLATE_FIELD_L4_DPORT, RTL931X_TEMPLATE_FIELD_VLAN, + RTL931X_TEMPLATE_FIELD_RANGE_CHK, RTL931X_TEMPLATE_FIELD_SPM0, RTL931X_TEMPLATE_FIELD_SPM1, + RTL931X_TEMPLATE_FIELD_SPM2, RTL931X_TEMPLATE_FIELD_SPM3 + }, { + RTL931X_TEMPLATE_FIELD_DMAC0, RTL931X_TEMPLATE_FIELD_DMAC1, RTL931X_TEMPLATE_FIELD_DMAC2, + RTL931X_TEMPLATE_FIELD_VLAN, RTL931X_TEMPLATE_FIELD_ETHERTYPE, RTL931X_TEMPLATE_FIELD_IP_TOS_PROTO, + RTL931X_TEMPLATE_FIELD_SIP0, RTL931X_TEMPLATE_FIELD_SIP1, RTL931X_TEMPLATE_FIELD_DIP0, + RTL931X_TEMPLATE_FIELD_DIP1, RTL931X_TEMPLATE_FIELD_L4_SPORT, RTL931X_TEMPLATE_FIELD_L4_DPORT, + RTL931X_TEMPLATE_FIELD_META_DATA, RTL931X_TEMPLATE_FIELD_SLP + }, { + RTL931X_TEMPLATE_FIELD_DIP0, RTL931X_TEMPLATE_FIELD_DIP1, RTL931X_TEMPLATE_FIELD_DIP2, + RTL931X_TEMPLATE_FIELD_DIP3, RTL931X_TEMPLATE_FIELD_DIP4, RTL931X_TEMPLATE_FIELD_DIP5, + RTL931X_TEMPLATE_FIELD_DIP6, RTL931X_TEMPLATE_FIELD_DIP7, RTL931X_TEMPLATE_FIELD_IP_TOS_PROTO, + RTL931X_TEMPLATE_FIELD_TCP_INFO, RTL931X_TEMPLATE_FIELD_L4_SPORT, RTL931X_TEMPLATE_FIELD_L4_DPORT, + RTL931X_TEMPLATE_FIELD_RANGE_CHK, RTL931X_TEMPLATE_FIELD_SLP + }, { + RTL931X_TEMPLATE_FIELD_SIP0, RTL931X_TEMPLATE_FIELD_SIP1, RTL931X_TEMPLATE_FIELD_SIP2, + RTL931X_TEMPLATE_FIELD_SIP3, RTL931X_TEMPLATE_FIELD_SIP4, RTL931X_TEMPLATE_FIELD_SIP5, + RTL931X_TEMPLATE_FIELD_SIP6, RTL931X_TEMPLATE_FIELD_SIP7, RTL931X_TEMPLATE_FIELD_META_DATA, + RTL931X_TEMPLATE_FIELD_VLAN, RTL931X_TEMPLATE_FIELD_SPM0, RTL931X_TEMPLATE_FIELD_SPM1, + RTL931X_TEMPLATE_FIELD_SPM2, RTL931X_TEMPLATE_FIELD_SPM3 + }, +}; + +static void rtl931x_pie_lookup_enable(struct rtl838x_switch_priv *priv, int index) +{ + int block = index / PIE_BLOCK_SIZE; + + sw_w32_mask(0, BIT(block), RTL931X_PIE_BLK_LOOKUP_CTRL); +} + +/* Fills the data in the intermediate representation in the pie_rule structure + * into a data field for a given template field field_type + * TODO: This function looks very similar to the function of the rtl9300, but + * since it uses the physical template_field_id, which are different for each + * SoC and there are other field types, it is actually not. If we would also use + * an intermediate representation for a field type, we would could have one + * pie_data_fill function for all SoCs, provided we have also for each SoC a + * function to map between physical and intermediate field type + */ +static int rtl931x_pie_data_fill(enum rtl931x_template_field_id field_type, struct pie_rule *pr, u16 *data, u16 *data_m) +{ + *data = *data_m = 0; + + switch (field_type) { + case RTL931X_TEMPLATE_FIELD_SPM0: + *data = pr->spm; + *data_m = pr->spm_m; + break; + case RTL931X_TEMPLATE_FIELD_SPM1: + *data = pr->spm >> 16; + *data_m = pr->spm_m >> 16; + break; + case RTL931X_TEMPLATE_FIELD_OTAG: + *data = pr->otag; + *data_m = pr->otag_m; + break; + case RTL931X_TEMPLATE_FIELD_SMAC0: + *data = pr->smac[4]; + *data = (*data << 8) | pr->smac[5]; + *data_m = pr->smac_m[4]; + *data_m = (*data_m << 8) | pr->smac_m[5]; + break; + case RTL931X_TEMPLATE_FIELD_SMAC1: + *data = pr->smac[2]; + *data = (*data << 8) | pr->smac[3]; + *data_m = pr->smac_m[2]; + *data_m = (*data_m << 8) | pr->smac_m[3]; + break; + case RTL931X_TEMPLATE_FIELD_SMAC2: + *data = pr->smac[0]; + *data = (*data << 8) | pr->smac[1]; + *data_m = pr->smac_m[0]; + *data_m = (*data_m << 8) | pr->smac_m[1]; + break; + case RTL931X_TEMPLATE_FIELD_DMAC0: + *data = pr->dmac[4]; + *data = (*data << 8) | pr->dmac[5]; + *data_m = pr->dmac_m[4]; + *data_m = (*data_m << 8) | pr->dmac_m[5]; + break; + case RTL931X_TEMPLATE_FIELD_DMAC1: + *data = pr->dmac[2]; + *data = (*data << 8) | pr->dmac[3]; + *data_m = pr->dmac_m[2]; + *data_m = (*data_m << 8) | pr->dmac_m[3]; + break; + case RTL931X_TEMPLATE_FIELD_DMAC2: + *data = pr->dmac[0]; + *data = (*data << 8) | pr->dmac[1]; + *data_m = pr->dmac_m[0]; + *data_m = (*data_m << 8) | pr->dmac_m[1]; + break; + case RTL931X_TEMPLATE_FIELD_ETHERTYPE: + *data = pr->ethertype; + *data_m = pr->ethertype_m; + break; + case RTL931X_TEMPLATE_FIELD_ITAG: + *data = pr->itag; + *data_m = pr->itag_m; + break; + case RTL931X_TEMPLATE_FIELD_SIP0: + if (pr->is_ipv6) { + *data = pr->sip6.s6_addr16[7]; + *data_m = pr->sip6_m.s6_addr16[7]; + } else { + *data = pr->sip; + *data_m = pr->sip_m; + } + break; + case RTL931X_TEMPLATE_FIELD_SIP1: + if (pr->is_ipv6) { + *data = pr->sip6.s6_addr16[6]; + *data_m = pr->sip6_m.s6_addr16[6]; + } else { + *data = pr->sip >> 16; + *data_m = pr->sip_m >> 16; + } + break; + case RTL931X_TEMPLATE_FIELD_SIP2: + case RTL931X_TEMPLATE_FIELD_SIP3: + case RTL931X_TEMPLATE_FIELD_SIP4: + case RTL931X_TEMPLATE_FIELD_SIP5: + case RTL931X_TEMPLATE_FIELD_SIP6: + case RTL931X_TEMPLATE_FIELD_SIP7: + *data = pr->sip6.s6_addr16[5 - (field_type - RTL931X_TEMPLATE_FIELD_SIP2)]; + *data_m = pr->sip6_m.s6_addr16[5 - (field_type - RTL931X_TEMPLATE_FIELD_SIP2)]; + break; + case RTL931X_TEMPLATE_FIELD_DIP0: + if (pr->is_ipv6) { + *data = pr->dip6.s6_addr16[7]; + *data_m = pr->dip6_m.s6_addr16[7]; + } else { + *data = pr->dip; + *data_m = pr->dip_m; + } + break; + case RTL931X_TEMPLATE_FIELD_DIP1: + if (pr->is_ipv6) { + *data = pr->dip6.s6_addr16[6]; + *data_m = pr->dip6_m.s6_addr16[6]; + } else { + *data = pr->dip >> 16; + *data_m = pr->dip_m >> 16; + } + break; + case RTL931X_TEMPLATE_FIELD_DIP2: + case RTL931X_TEMPLATE_FIELD_DIP3: + case RTL931X_TEMPLATE_FIELD_DIP4: + case RTL931X_TEMPLATE_FIELD_DIP5: + case RTL931X_TEMPLATE_FIELD_DIP6: + case RTL931X_TEMPLATE_FIELD_DIP7: + *data = pr->dip6.s6_addr16[5 - (field_type - RTL931X_TEMPLATE_FIELD_DIP2)]; + *data_m = pr->dip6_m.s6_addr16[5 - (field_type - RTL931X_TEMPLATE_FIELD_DIP2)]; + break; + case RTL931X_TEMPLATE_FIELD_IP_TOS_PROTO: + *data = pr->tos_proto; + *data_m = pr->tos_proto_m; + break; + case RTL931X_TEMPLATE_FIELD_L4_SPORT: + *data = pr->sport; + *data_m = pr->sport_m; + break; + case RTL931X_TEMPLATE_FIELD_L4_DPORT: + *data = pr->dport; + *data_m = pr->dport_m; + break; + case RTL931X_TEMPLATE_FIELD_DSAP_SSAP: + *data = pr->dsap_ssap; + *data_m = pr->dsap_ssap_m; + break; + case RTL931X_TEMPLATE_FIELD_TCP_INFO: + *data = pr->tcp_info; + *data_m = pr->tcp_info_m; + break; + case RTL931X_TEMPLATE_FIELD_RANGE_CHK: + pr_debug("RTL931X_TEMPLATE_FIELD_RANGE_CHK: not configured\n"); + break; + default: + pr_debug("%s: unknown field %d\n", __func__, field_type); + return -1; + } + + return 0; +} + +/* Reads the intermediate representation of the templated match-fields of the + * PIE rule in the pie_rule structure and fills in the raw data fields in the + * raw register space r[]. + * The register space configuration size is identical for the RTL8380/90 and RTL9300, + * however the RTL931X has 2 more registers / fields and the physical field-ids are different + * on all SoCs + * On the RTL9300 the mask fields are not word-aligend! + */ +static void rtl931x_write_pie_templated(u32 r[], struct pie_rule *pr, enum rtl931x_template_field_id t[]) +{ + for (int i = 0; i < N_FIXED_FIELDS; i++) { + u16 data, data_m; + + rtl931x_pie_data_fill(t[i], pr, &data, &data_m); + + /* On the RTL9300, the mask fields are not word aligned! */ + if (!(i % 2)) { + r[5 - i / 2] = data; + r[12 - i / 2] |= ((u32)data_m << 8); + } else { + r[5 - i / 2] |= ((u32)data) << 16; + r[12 - i / 2] |= ((u32)data_m) << 24; + r[11 - i / 2] |= ((u32)data_m) >> 8; + } + } +} + +// Currently unused +// static void rtl931x_read_pie_fixed_fields(u32 r[], struct pie_rule *pr) +// { +// pr->mgnt_vlan = r[7] & BIT(31); +// if (pr->phase == PHASE_IACL) +// pr->dmac_hit_sw = r[7] & BIT(30); +// else /* TODO: EACL/VACL phase handling */ +// pr->content_too_deep = r[7] & BIT(30); +// pr->not_first_frag = r[7] & BIT(29); +// pr->frame_type_l4 = (r[7] >> 26) & 7; +// pr->frame_type = (r[7] >> 24) & 3; +// pr->otag_fmt = (r[7] >> 23) & 1; +// pr->itag_fmt = (r[7] >> 22) & 1; +// pr->otag_exist = (r[7] >> 21) & 1; +// pr->itag_exist = (r[7] >> 20) & 1; +// pr->frame_type_l2 = (r[7] >> 18) & 3; +// pr->igr_normal_port = (r[7] >> 17) & 1; +// pr->tid = (r[7] >> 16) & 1; + +// pr->mgnt_vlan_m = r[14] & BIT(15); +// if (pr->phase == PHASE_IACL) +// pr->dmac_hit_sw_m = r[14] & BIT(14); +// else +// pr->content_too_deep_m = r[14] & BIT(14); +// pr->not_first_frag_m = r[14] & BIT(13); +// pr->frame_type_l4_m = (r[14] >> 10) & 7; +// pr->frame_type_m = (r[14] >> 8) & 3; +// pr->otag_fmt_m = r[14] & BIT(7); +// pr->itag_fmt_m = r[14] & BIT(6); +// pr->otag_exist_m = r[14] & BIT(5); +// pr->itag_exist_m = r[14] & BIT (4); +// pr->frame_type_l2_m = (r[14] >> 2) & 3; +// pr->igr_normal_port_m = r[14] & BIT(1); +// pr->tid_m = r[14] & 1; + +// pr->valid = r[15] & BIT(31); +// pr->cond_not = r[15] & BIT(30); +// pr->cond_and1 = r[15] & BIT(29); +// pr->cond_and2 = r[15] & BIT(28); +// } + +static void rtl931x_write_pie_fixed_fields(u32 r[], struct pie_rule *pr) +{ + r[7] |= pr->mgnt_vlan ? BIT(31) : 0; + if (pr->phase == PHASE_IACL) + r[7] |= pr->dmac_hit_sw ? BIT(30) : 0; + else + r[7] |= pr->content_too_deep ? BIT(30) : 0; + r[7] |= pr->not_first_frag ? BIT(29) : 0; + r[7] |= ((u32)(pr->frame_type_l4 & 0x7)) << 26; + r[7] |= ((u32)(pr->frame_type & 0x3)) << 24; + r[7] |= pr->otag_fmt ? BIT(23) : 0; + r[7] |= pr->itag_fmt ? BIT(22) : 0; + r[7] |= pr->otag_exist ? BIT(21) : 0; + r[7] |= pr->itag_exist ? BIT(20) : 0; + r[7] |= ((u32)(pr->frame_type_l2 & 0x3)) << 18; + r[7] |= pr->igr_normal_port ? BIT(17) : 0; + r[7] |= ((u32)(pr->tid & 0x1)) << 16; + + r[14] |= pr->mgnt_vlan_m ? BIT(15) : 0; + if (pr->phase == PHASE_IACL) + r[14] |= pr->dmac_hit_sw_m ? BIT(14) : 0; + else + r[14] |= pr->content_too_deep_m ? BIT(14) : 0; + r[14] |= pr->not_first_frag_m ? BIT(13) : 0; + r[14] |= ((u32)(pr->frame_type_l4_m & 0x7)) << 10; + r[14] |= ((u32)(pr->frame_type_m & 0x3)) << 8; + r[14] |= pr->otag_fmt_m ? BIT(7) : 0; + r[14] |= pr->itag_fmt_m ? BIT(6) : 0; + r[14] |= pr->otag_exist_m ? BIT(5) : 0; + r[14] |= pr->itag_exist_m ? BIT(4) : 0; + r[14] |= ((u32)(pr->frame_type_l2_m & 0x3)) << 2; + r[14] |= pr->igr_normal_port_m ? BIT(1) : 0; + r[14] |= (u32)(pr->tid_m & 0x1); + + r[15] |= pr->valid ? BIT(31) : 0; + r[15] |= pr->cond_not ? BIT(30) : 0; + r[15] |= pr->cond_and1 ? BIT(29) : 0; + r[15] |= pr->cond_and2 ? BIT(28) : 0; +} + +static void rtl931x_write_pie_action(u32 r[], struct pie_rule *pr) +{ + /* Either drop or forward */ + if (pr->drop) { + r[15] |= BIT(11) | BIT(12) | BIT(13); /* Do Green, Yellow and Red drops */ + /* Actually DROP, not PERMIT in Green / Yellow / Red */ + r[16] |= BIT(27) | BIT(28) | BIT(29); + } else { + r[15] |= pr->fwd_sel ? BIT(14) : 0; + r[16] |= pr->fwd_act << 24; + r[16] |= BIT(21); /* We overwrite any drop */ + } + if (pr->phase == PHASE_VACL) + r[16] |= pr->fwd_sa_lrn ? BIT(22) : 0; + r[15] |= pr->bypass_sel ? BIT(10) : 0; + r[15] |= pr->nopri_sel ? BIT(21) : 0; + r[15] |= pr->tagst_sel ? BIT(20) : 0; + r[15] |= pr->ovid_sel ? BIT(18) : 0; + r[15] |= pr->ivid_sel ? BIT(16) : 0; + r[15] |= pr->meter_sel ? BIT(27) : 0; + r[15] |= pr->mir_sel ? BIT(15) : 0; + r[15] |= pr->log_sel ? BIT(26) : 0; + + r[16] |= ((u32)(pr->fwd_data & 0xfff)) << 9; +/* r[15] |= pr->log_octets ? BIT(31) : 0; */ + r[15] |= (u32)(pr->meter_data) >> 2; + r[16] |= (((u32)(pr->meter_data) >> 7) & 0x3) << 29; + + r[16] |= ((u32)(pr->ivid_act & 0x3)) << 21; + r[15] |= ((u32)(pr->ivid_data & 0xfff)) << 9; + r[16] |= ((u32)(pr->ovid_act & 0x3)) << 30; + r[16] |= ((u32)(pr->ovid_data & 0xfff)) << 16; + r[16] |= ((u32)(pr->mir_data & 0x3)) << 6; + r[17] |= ((u32)(pr->tagst_data & 0xf)) << 28; + r[17] |= ((u32)(pr->nopri_data & 0x7)) << 25; + r[17] |= pr->bypass_ibc_sc ? BIT(16) : 0; +} + +static void rtl931x_pie_rule_dump_raw(u32 r[]) +{ + pr_debug("Raw IACL table entry:\n"); + pr_debug("r 0 - 7: %08x %08x %08x %08x %08x %08x %08x %08x\n", + r[0], r[1], r[2], r[3], r[4], r[5], r[6], r[7]); + pr_debug("r 8 - 15: %08x %08x %08x %08x %08x %08x %08x %08x\n", + r[8], r[9], r[10], r[11], r[12], r[13], r[14], r[15]); + pr_debug("r 16 - 18: %08x %08x %08x\n", r[16], r[17], r[18]); + pr_debug("Match : %08x %08x %08x %08x %08x %08x\n", r[0], r[1], r[2], r[3], r[4], r[5]); + pr_debug("Fixed : %06x\n", r[6] >> 8); + pr_debug("Match M: %08x %08x %08x %08x %08x %08x\n", + (r[6] << 24) | (r[7] >> 8), (r[7] << 24) | (r[8] >> 8), (r[8] << 24) | (r[9] >> 8), + (r[9] << 24) | (r[10] >> 8), (r[10] << 24) | (r[11] >> 8), + (r[11] << 24) | (r[12] >> 8)); + pr_debug("R[13]: %08x\n", r[13]); + pr_debug("Fixed M: %06x\n", ((r[12] << 16) | (r[13] >> 16)) & 0xffffff); + pr_debug("Valid / not / and1 / and2 : %1x\n", (r[13] >> 12) & 0xf); + pr_debug("r 13-16: %08x %08x %08x %08x\n", r[13], r[14], r[15], r[16]); +} + +int rtl931x_pie_rule_write(struct rtl838x_switch_priv *priv, int idx, struct pie_rule *pr) +{ + int tbl = otto_table_acquire(RTL9310_TBL_IACL); + u32 r[22]; + int block = idx / PIE_BLOCK_SIZE; + u32 t_select = sw_r32(RTL931X_PIE_BLK_TMPLTE_CTRL(block)); + + pr_debug("%s: %d, t_select: %08x\n", __func__, idx, t_select); + + for (int i = 0; i < 22; i++) + r[i] = 0; + + if (!pr->valid) { + __otto_table_write(tbl, idx, &r); + otto_table_release(tbl); + return 0; + } + rtl931x_write_pie_fixed_fields(r, pr); + + pr_debug("%s: template %d\n", __func__, (t_select >> (pr->tid * 4)) & 0xf); + rtl931x_write_pie_templated(r, pr, rtl931x_fixed_templates[(t_select >> (pr->tid * 4)) & 0xf]); + + rtl931x_write_pie_action(r, pr); + + rtl931x_pie_rule_dump_raw(r); + + __otto_table_write(tbl, idx, &r); + otto_table_release(tbl); + + return 0; +} + +static bool rtl931x_pie_templ_has(int t, enum rtl931x_template_field_id field_type) +{ + for (int i = 0; i < N_FIXED_FIELDS_RTL931X; i++) { + enum rtl931x_template_field_id ft = rtl931x_fixed_templates[t][i]; + + if (field_type == ft) + return true; + } + + return false; +} + +/* Verify that the rule pr is compatible with a given template t in block + * Note that this function is SoC specific since the values of e.g. RTL931X_TEMPLATE_FIELD_SIP0 + * depend on the SoC + */ +static int rtl931x_pie_verify_template(struct rtl838x_switch_priv *priv, + struct pie_rule *pr, int t, int block) +{ + int i; + + if (!pr->is_ipv6 && pr->sip_m && !rtl931x_pie_templ_has(t, RTL931X_TEMPLATE_FIELD_SIP0)) + return -1; + + if (!pr->is_ipv6 && pr->dip_m && !rtl931x_pie_templ_has(t, RTL931X_TEMPLATE_FIELD_DIP0)) + return -1; + + if (pr->is_ipv6) { + if ((pr->sip6_m.s6_addr32[0] || + pr->sip6_m.s6_addr32[1] || + pr->sip6_m.s6_addr32[2] || + pr->sip6_m.s6_addr32[3]) && + !rtl931x_pie_templ_has(t, RTL931X_TEMPLATE_FIELD_SIP2)) + return -1; + if ((pr->dip6_m.s6_addr32[0] || + pr->dip6_m.s6_addr32[1] || + pr->dip6_m.s6_addr32[2] || + pr->dip6_m.s6_addr32[3]) && + !rtl931x_pie_templ_has(t, RTL931X_TEMPLATE_FIELD_DIP2)) + return -1; + } + + if (ether_addr_to_u64(pr->smac_m) && !rtl931x_pie_templ_has(t, RTL931X_TEMPLATE_FIELD_SMAC0)) + return -1; + + if (ether_addr_to_u64(pr->dmac_m) && !rtl931x_pie_templ_has(t, RTL931X_TEMPLATE_FIELD_DMAC0)) + return -1; + + if (pr->itag_m && !rtl931x_pie_templ_has(t, RTL931X_TEMPLATE_FIELD_VLAN)) + return -1; + + if (pr->sport_m && !rtl931x_pie_templ_has(t, RTL931X_TEMPLATE_FIELD_L4_SPORT)) + return -1; + + if (pr->dport_m && !rtl931x_pie_templ_has(t, RTL931X_TEMPLATE_FIELD_L4_DPORT)) + return -1; + + /* TODO: Check more */ + + i = find_first_zero_bit(&priv->pie_use_bm[block * 4], PIE_BLOCK_SIZE); + + if (i >= PIE_BLOCK_SIZE) + return -1; + + return i + PIE_BLOCK_SIZE * block; +} + +int rtl931x_pie_rule_add(struct rtl838x_switch_priv *priv, struct pie_rule *pr) +{ + int idx, block, j; + int min_block = 0; + int max_block = priv->r->n_pie_blocks / 2; + + if (pr->is_egress) { + min_block = max_block; + max_block = priv->r->n_pie_blocks; + } + pr_debug("In %s\n", __func__); + + mutex_lock(&priv->pie_mutex); + + for (block = min_block; block < max_block; block++) { + for (j = 0; j < 2; j++) { + int t = (sw_r32(RTL931X_PIE_BLK_TMPLTE_CTRL(block)) >> (j * 4)) & 0xf; + + pr_debug("Testing block %d, template %d, template id %d\n", block, j, t); + pr_debug("%s: %08x\n", + __func__, sw_r32(RTL931X_PIE_BLK_TMPLTE_CTRL(block))); + idx = rtl931x_pie_verify_template(priv, pr, t, block); + if (idx >= 0) + break; + } + if (j < 2) + break; + } + + if (block >= max_block) { + mutex_unlock(&priv->pie_mutex); + return -EOPNOTSUPP; + } + + pr_debug("Using block: %d, index %d, template-id %d\n", block, idx, j); + set_bit(idx, priv->pie_use_bm); + + pr->valid = true; + pr->tid = j; /* Mapped to template number */ + pr->tid_m = 0x1; + pr->id = idx; + + rtl931x_pie_lookup_enable(priv, idx); + rtl931x_pie_rule_write(priv, idx, pr); + + mutex_unlock(&priv->pie_mutex); + + return 0; +} + +/* Delete a range of Packet Inspection Engine rules */ +static int rtl931x_pie_rule_del(struct rtl838x_switch_priv *priv, int index_from, int index_to) +{ + u32 v = (index_from << 1) | (index_to << 13) | BIT(0); + + pr_debug("%s: from %d to %d\n", __func__, index_from, index_to); + mutex_lock(&priv->reg_mutex); + + /* Write from-to and execute bit into control register */ + sw_w32(v, RTL931X_PIE_CLR_CTRL); + + /* Wait until command has completed */ + do { + } while (sw_r32(RTL931X_PIE_CLR_CTRL) & BIT(0)); + + mutex_unlock(&priv->reg_mutex); + + return 0; +} + +void rtl931x_pie_rule_rm(struct rtl838x_switch_priv *priv, struct pie_rule *pr) +{ + int idx = pr->id; + + rtl931x_pie_rule_del(priv, idx, idx); + clear_bit(idx, priv->pie_use_bm); +} + +void rtl931x_pie_init(struct rtl838x_switch_priv *priv) +{ + u32 template_selectors; + + mutex_init(&priv->pie_mutex); + + pr_debug("%s\n", __func__); + /* Enable ACL lookup on all ports, including CPU_PORT */ + for (int i = 0; i <= priv->r->cpu_port; i++) + sw_w32(1, RTL931X_ACL_PORT_LOOKUP_CTRL(i)); + + /* Include IPG in metering */ + sw_w32_mask(0, 1, RTL931X_METER_GLB_CTRL); + + /* Delete all present rules, block size is 128 on all SoC families */ + rtl931x_pie_rule_del(priv, 0, priv->r->n_pie_blocks * 128 - 1); + + /* Assign first half blocks 0-7 to VACL phase, second half to IACL */ + /* 3 bits are used for each block, values for PIE blocks are */ + /* 6: Disabled, 0: VACL, 1: IACL, 2: EACL */ + /* And for OpenFlow Flow blocks: 3: Ingress Flow table 0, */ + /* 4: Ingress Flow Table 3, 5: Egress flow table 0 */ + for (int i = 0; i < priv->r->n_pie_blocks; i++) { + int pos = (i % 10) * 3; + u32 r = RTL931X_PIE_BLK_PHASE_CTRL + 4 * (i / 10); + + if (i < priv->r->n_pie_blocks / 2) + sw_w32_mask(0x7 << pos, 0, r); + else + sw_w32_mask(0x7 << pos, 1 << pos, r); + } + + /* Enable predefined templates 0, 1 for first quarter of all blocks */ + template_selectors = 0 | (1 << 4); + for (int i = 0; i < priv->r->n_pie_blocks / 4; i++) + sw_w32(template_selectors, RTL931X_PIE_BLK_TMPLTE_CTRL(i)); + + /* Enable predefined templates 2, 3 for second quarter of all blocks */ + template_selectors = 2 | (3 << 4); + for (int i = priv->r->n_pie_blocks / 4; i < priv->r->n_pie_blocks / 2; i++) + sw_w32(template_selectors, RTL931X_PIE_BLK_TMPLTE_CTRL(i)); + + /* Enable predefined templates 0, 1 for third quater of all blocks */ + template_selectors = 0 | (1 << 4); + for (int i = priv->r->n_pie_blocks / 2; i < priv->r->n_pie_blocks * 3 / 4; i++) + sw_w32(template_selectors, RTL931X_PIE_BLK_TMPLTE_CTRL(i)); + + /* Enable predefined templates 2, 3 for fourth quater of all blocks */ + template_selectors = 2 | (3 << 4); + for (int i = priv->r->n_pie_blocks * 3 / 4; i < priv->r->n_pie_blocks; i++) + sw_w32(template_selectors, RTL931X_PIE_BLK_TMPLTE_CTRL(i)); +} diff --git a/target/linux/realtek/files-6.18/drivers/net/dsa/rtl83xx/pie.h b/target/linux/realtek/files-6.18/drivers/net/dsa/rtl83xx/pie.h new file mode 100644 index 00000000000..d4157519b9b --- /dev/null +++ b/target/linux/realtek/files-6.18/drivers/net/dsa/rtl83xx/pie.h @@ -0,0 +1,40 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +#ifndef _OTTO_PIE_H +#define _OTTO_PIE_H + +#include + +struct pie_rule; +struct rtl838x_switch_priv; + +void rtl838x_pie_init(struct rtl838x_switch_priv *priv); +int rtl838x_pie_rule_read(struct rtl838x_switch_priv *priv, int idx, + struct pie_rule *pr); +int rtl838x_pie_rule_write(struct rtl838x_switch_priv *priv, int idx, + struct pie_rule *pr); +int rtl838x_pie_rule_add(struct rtl838x_switch_priv *priv, struct pie_rule *pr); +void rtl838x_pie_rule_rm(struct rtl838x_switch_priv *priv, struct pie_rule *pr); + +void rtl839x_pie_init(struct rtl838x_switch_priv *priv); +int rtl839x_pie_rule_read(struct rtl838x_switch_priv *priv, int idx, + struct pie_rule *pr); +int rtl839x_pie_rule_write(struct rtl838x_switch_priv *priv, int idx, + struct pie_rule *pr); +int rtl839x_pie_rule_add(struct rtl838x_switch_priv *priv, struct pie_rule *pr); +void rtl839x_pie_rule_rm(struct rtl838x_switch_priv *priv, struct pie_rule *pr); +void rtl839x_pie_rule_dump(struct pie_rule *pr); + +void rtl930x_pie_init(struct rtl838x_switch_priv *priv); +int rtl930x_pie_rule_write(struct rtl838x_switch_priv *priv, int idx, + struct pie_rule *pr); +int rtl930x_pie_rule_add(struct rtl838x_switch_priv *priv, struct pie_rule *pr); +void rtl930x_pie_rule_rm(struct rtl838x_switch_priv *priv, struct pie_rule *pr); +void rtl930x_pie_rule_dump_raw(u32 r[]); + +void rtl931x_pie_init(struct rtl838x_switch_priv *priv); +int rtl931x_pie_rule_write(struct rtl838x_switch_priv *priv, int idx, + struct pie_rule *pr); +int rtl931x_pie_rule_add(struct rtl838x_switch_priv *priv, struct pie_rule *pr); +void rtl931x_pie_rule_rm(struct rtl838x_switch_priv *priv, struct pie_rule *pr); + +#endif /* _OTTO_PIE_H */ diff --git a/target/linux/realtek/files-6.18/drivers/net/dsa/rtl83xx/rtl-otto.h b/target/linux/realtek/files-6.18/drivers/net/dsa/rtl83xx/rtl-otto.h index 261d46b5051..84f1cbed4d4 100644 --- a/target/linux/realtek/files-6.18/drivers/net/dsa/rtl83xx/rtl-otto.h +++ b/target/linux/realtek/files-6.18/drivers/net/dsa/rtl83xx/rtl-otto.h @@ -1627,11 +1627,9 @@ int rtl83xx_lag_del(struct dsa_switch *ds, int group, int port); * collect them in this section. */ -void rtl839x_pie_rule_dump(struct pie_rule *pr); void rtl839x_set_egress_queue(int port, int queue); void rtl9300_dump_debug(void); -void rtl930x_pie_rule_dump_raw(u32 r[]); extern const struct dsa_switch_ops rtldsa_83xx_switch_ops; extern const struct dsa_switch_ops rtldsa_93xx_switch_ops; diff --git a/target/linux/realtek/files-6.18/drivers/net/dsa/rtl83xx/rtl838x.c b/target/linux/realtek/files-6.18/drivers/net/dsa/rtl83xx/rtl838x.c index 00fa98d02ae..162158061b6 100644 --- a/target/linux/realtek/files-6.18/drivers/net/dsa/rtl83xx/rtl838x.c +++ b/target/linux/realtek/files-6.18/drivers/net/dsa/rtl83xx/rtl838x.c @@ -6,97 +6,10 @@ #include #include "l3.h" +#include "pie.h" #include "rtl-otto.h" #include "vlan.h" -/* see_dal_maple_acl_log2PhyTmplteField and src/app/diag_v2/src/diag_acl.c */ -/* Definition of the RTL838X-specific template field IDs as used in the PIE */ -enum rtl838x_template_field_id { - RTL838X_TEMPLATE_FIELD_SPMMASK = 0, - RTL838X_TEMPLATE_FIELD_SPM0 = 1, /* Source portmask ports 0-15 */ - RTL838X_TEMPLATE_FIELD_SPM1 = 2, /* Source portmask ports 16-28 */ - RTL838X_TEMPLATE_FIELD_RANGE_CHK = 3, - RTL838X_TEMPLATE_FIELD_DMAC0 = 4, /* Destination MAC [15:0] */ - RTL838X_TEMPLATE_FIELD_DMAC1 = 5, /* Destination MAC [31:16] */ - RTL838X_TEMPLATE_FIELD_DMAC2 = 6, /* Destination MAC [47:32] */ - RTL838X_TEMPLATE_FIELD_SMAC0 = 7, /* Source MAC [15:0] */ - RTL838X_TEMPLATE_FIELD_SMAC1 = 8, /* Source MAC [31:16] */ - RTL838X_TEMPLATE_FIELD_SMAC2 = 9, /* Source MAC [47:32] */ - RTL838X_TEMPLATE_FIELD_ETHERTYPE = 10, /* Ethernet typ */ - RTL838X_TEMPLATE_FIELD_OTAG = 11, /* Outer VLAN tag */ - RTL838X_TEMPLATE_FIELD_ITAG = 12, /* Inner VLAN tag */ - RTL838X_TEMPLATE_FIELD_SIP0 = 13, /* IPv4 or IPv6 source IP[15:0] or ARP/RARP */ - /* source protocol address in header */ - RTL838X_TEMPLATE_FIELD_SIP1 = 14, /* IPv4 or IPv6 source IP[31:16] or ARP/RARP */ - RTL838X_TEMPLATE_FIELD_DIP0 = 15, /* IPv4 or IPv6 destination IP[15:0] */ - RTL838X_TEMPLATE_FIELD_DIP1 = 16, /* IPv4 or IPv6 destination IP[31:16] */ - RTL838X_TEMPLATE_FIELD_IP_TOS_PROTO = 17, /* IPv4 TOS/IPv6 traffic class and */ - /* IPv4 proto/IPv6 next header fields */ - RTL838X_TEMPLATE_FIELD_L34_HEADER = 18, /* packet with extra tag and IPv6 with auth, dest, */ - /* frag, route, hop-by-hop option header, */ - /* IGMP type, TCP flag */ - RTL838X_TEMPLATE_FIELD_L4_SPORT = 19, /* TCP/UDP source port */ - RTL838X_TEMPLATE_FIELD_L4_DPORT = 20, /* TCP/UDP destination port */ - RTL838X_TEMPLATE_FIELD_ICMP_IGMP = 21, - RTL838X_TEMPLATE_FIELD_IP_RANGE = 22, - RTL838X_TEMPLATE_FIELD_FIELD_SELECTOR_VALID = 23, /* Field selector mask */ - RTL838X_TEMPLATE_FIELD_FIELD_SELECTOR_0 = 24, - RTL838X_TEMPLATE_FIELD_FIELD_SELECTOR_1 = 25, - RTL838X_TEMPLATE_FIELD_FIELD_SELECTOR_2 = 26, - RTL838X_TEMPLATE_FIELD_FIELD_SELECTOR_3 = 27, - RTL838X_TEMPLATE_FIELD_SIP2 = 28, /* IPv6 source IP[47:32] */ - RTL838X_TEMPLATE_FIELD_SIP3 = 29, /* IPv6 source IP[63:48] */ - RTL838X_TEMPLATE_FIELD_SIP4 = 30, /* IPv6 source IP[79:64] */ - RTL838X_TEMPLATE_FIELD_SIP5 = 31, /* IPv6 source IP[95:80] */ - RTL838X_TEMPLATE_FIELD_SIP6 = 32, /* IPv6 source IP[111:96] */ - RTL838X_TEMPLATE_FIELD_SIP7 = 33, /* IPv6 source IP[127:112] */ - RTL838X_TEMPLATE_FIELD_DIP2 = 34, /* IPv6 destination IP[47:32] */ - RTL838X_TEMPLATE_FIELD_DIP3 = 35, /* IPv6 destination IP[63:48] */ - RTL838X_TEMPLATE_FIELD_DIP4 = 36, /* IPv6 destination IP[79:64] */ - RTL838X_TEMPLATE_FIELD_DIP5 = 37, /* IPv6 destination IP[95:80] */ - RTL838X_TEMPLATE_FIELD_DIP6 = 38, /* IPv6 destination IP[111:96] */ - RTL838X_TEMPLATE_FIELD_DIP7 = 39, /* IPv6 destination IP[127:112] */ - RTL838X_TEMPLATE_FIELD_FWD_VID = 40, /* Forwarding VLAN-ID */ - RTL838X_TEMPLATE_FIELD_FLOW_LABEL = 41, -}; - -/* The RTL838X SoCs use 5 fixed templates with definitions for which data fields are to - * be copied from the Ethernet Frame header into the 12 User-definable fields of the Packet - * Inspection Engine's buffer. The following defines the field contents for each of the fixed - * templates. Additionally, 3 user-definable templates can be set up via the definitions - * in RTL838X_ACL_TMPLTE_CTRL control registers. - * TODO: See all src/app/diag_v2/src/diag_pie.c - */ -#define RTL838X_N_FIXED_TEMPLATES 5 -static enum rtl838x_template_field_id rtl838x_fixed_templates[RTL838X_N_FIXED_TEMPLATES][N_FIXED_FIELDS] = { - { - RTL838X_TEMPLATE_FIELD_SPM0, RTL838X_TEMPLATE_FIELD_SPM1, RTL838X_TEMPLATE_FIELD_OTAG, - RTL838X_TEMPLATE_FIELD_SMAC0, RTL838X_TEMPLATE_FIELD_SMAC1, RTL838X_TEMPLATE_FIELD_SMAC2, - RTL838X_TEMPLATE_FIELD_DMAC0, RTL838X_TEMPLATE_FIELD_DMAC1, RTL838X_TEMPLATE_FIELD_DMAC2, - RTL838X_TEMPLATE_FIELD_ETHERTYPE, RTL838X_TEMPLATE_FIELD_ITAG, RTL838X_TEMPLATE_FIELD_RANGE_CHK - }, { - RTL838X_TEMPLATE_FIELD_SIP0, RTL838X_TEMPLATE_FIELD_SIP1, RTL838X_TEMPLATE_FIELD_DIP0, - RTL838X_TEMPLATE_FIELD_DIP1, RTL838X_TEMPLATE_FIELD_IP_TOS_PROTO, RTL838X_TEMPLATE_FIELD_L4_SPORT, - RTL838X_TEMPLATE_FIELD_L4_DPORT, RTL838X_TEMPLATE_FIELD_ICMP_IGMP, RTL838X_TEMPLATE_FIELD_ITAG, - RTL838X_TEMPLATE_FIELD_RANGE_CHK, RTL838X_TEMPLATE_FIELD_SPM0, RTL838X_TEMPLATE_FIELD_SPM1 - }, { - RTL838X_TEMPLATE_FIELD_DMAC0, RTL838X_TEMPLATE_FIELD_DMAC1, RTL838X_TEMPLATE_FIELD_DMAC2, - RTL838X_TEMPLATE_FIELD_ITAG, RTL838X_TEMPLATE_FIELD_ETHERTYPE, RTL838X_TEMPLATE_FIELD_IP_TOS_PROTO, - RTL838X_TEMPLATE_FIELD_L4_DPORT, RTL838X_TEMPLATE_FIELD_L4_SPORT, RTL838X_TEMPLATE_FIELD_SIP0, - RTL838X_TEMPLATE_FIELD_SIP1, RTL838X_TEMPLATE_FIELD_DIP0, RTL838X_TEMPLATE_FIELD_DIP1 - }, { - RTL838X_TEMPLATE_FIELD_DIP0, RTL838X_TEMPLATE_FIELD_DIP1, RTL838X_TEMPLATE_FIELD_DIP2, - RTL838X_TEMPLATE_FIELD_DIP3, RTL838X_TEMPLATE_FIELD_DIP4, RTL838X_TEMPLATE_FIELD_DIP5, - RTL838X_TEMPLATE_FIELD_DIP6, RTL838X_TEMPLATE_FIELD_DIP7, RTL838X_TEMPLATE_FIELD_L4_DPORT, - RTL838X_TEMPLATE_FIELD_L4_SPORT, RTL838X_TEMPLATE_FIELD_ICMP_IGMP, RTL838X_TEMPLATE_FIELD_IP_TOS_PROTO - }, { - RTL838X_TEMPLATE_FIELD_SIP0, RTL838X_TEMPLATE_FIELD_SIP1, RTL838X_TEMPLATE_FIELD_SIP2, - RTL838X_TEMPLATE_FIELD_SIP3, RTL838X_TEMPLATE_FIELD_SIP4, RTL838X_TEMPLATE_FIELD_SIP5, - RTL838X_TEMPLATE_FIELD_SIP6, RTL838X_TEMPLATE_FIELD_SIP7, RTL838X_TEMPLATE_FIELD_ITAG, - RTL838X_TEMPLATE_FIELD_RANGE_CHK, RTL838X_TEMPLATE_FIELD_SPM0, RTL838X_TEMPLATE_FIELD_SPM1 - }, -}; - const struct rtldsa_mib_list_item rtldsa_838x_mib_list[] = { MIB_LIST_ITEM("dot1dTpPortInDiscards", MIB_ITEM(MIB_REG_STD, 0xec, 1)), MIB_LIST_ITEM("ifOutDiscards", MIB_ITEM(MIB_REG_STD, 0xd0, 1)), @@ -594,880 +507,6 @@ static void rtl838x_init_eee(struct rtl838x_switch_priv *priv, bool enable) priv->eee_enabled = enable; } -static void rtl838x_pie_lookup_enable(struct rtl838x_switch_priv *priv, int index) -{ - int block = index / PIE_BLOCK_SIZE; - u32 block_state = sw_r32(RTL838X_ACL_BLK_LOOKUP_CTRL); - - /* Make sure rule-lookup is enabled in the block */ - if (!(block_state & BIT(block))) - sw_w32(block_state | BIT(block), RTL838X_ACL_BLK_LOOKUP_CTRL); -} - -static void rtl838x_pie_rule_del(struct rtl838x_switch_priv *priv, int index_from, int index_to) -{ - int block_from = index_from / PIE_BLOCK_SIZE; - int block_to = index_to / PIE_BLOCK_SIZE; - u32 v = (index_from << 1) | (index_to << 12) | BIT(0); - u32 block_state; - - pr_debug("%s: from %d to %d\n", __func__, index_from, index_to); - mutex_lock(&priv->reg_mutex); - - /* Remember currently active blocks */ - block_state = sw_r32(RTL838X_ACL_BLK_LOOKUP_CTRL); - - /* Make sure rule-lookup is disabled in the relevant blocks */ - for (int block = block_from; block <= block_to; block++) { - if (block_state & BIT(block)) - sw_w32(block_state & (~BIT(block)), RTL838X_ACL_BLK_LOOKUP_CTRL); - } - - /* Write from-to and execute bit into control register */ - sw_w32(v, RTL838X_ACL_CLR_CTRL); - - /* Wait until command has completed */ - do { - } while (sw_r32(RTL838X_ACL_CLR_CTRL) & BIT(0)); - - /* Re-enable rule lookup */ - for (int block = block_from; block <= block_to; block++) { - if (!(block_state & BIT(block))) - sw_w32(block_state | BIT(block), RTL838X_ACL_BLK_LOOKUP_CTRL); - } - - mutex_unlock(&priv->reg_mutex); -} - -/* Reads the intermediate representation of the templated match-fields of the - * PIE rule in the pie_rule structure and fills in the raw data fields in the - * raw register space r[]. - * The register space configuration size is identical for the RTL8380/90 and RTL9300, - * however the RTL9310 has 2 more registers / fields and the physical field-ids - * are specific to every platform. - */ -static void rtl838x_write_pie_templated(u32 r[], struct pie_rule *pr, enum rtl838x_template_field_id t[]) -{ - for (int i = 0; i < N_FIXED_FIELDS; i++) { - enum rtl838x_template_field_id field_type = t[i]; - u16 data = 0, data_m = 0; - - switch (field_type) { - case RTL838X_TEMPLATE_FIELD_SPM0: - data = pr->spm; - data_m = pr->spm_m; - break; - case RTL838X_TEMPLATE_FIELD_SPM1: - data = pr->spm >> 16; - data_m = pr->spm_m >> 16; - break; - case RTL838X_TEMPLATE_FIELD_OTAG: - data = pr->otag; - data_m = pr->otag_m; - break; - case RTL838X_TEMPLATE_FIELD_SMAC0: - data = pr->smac[4]; - data = (data << 8) | pr->smac[5]; - data_m = pr->smac_m[4]; - data_m = (data_m << 8) | pr->smac_m[5]; - break; - case RTL838X_TEMPLATE_FIELD_SMAC1: - data = pr->smac[2]; - data = (data << 8) | pr->smac[3]; - data_m = pr->smac_m[2]; - data_m = (data_m << 8) | pr->smac_m[3]; - break; - case RTL838X_TEMPLATE_FIELD_SMAC2: - data = pr->smac[0]; - data = (data << 8) | pr->smac[1]; - data_m = pr->smac_m[0]; - data_m = (data_m << 8) | pr->smac_m[1]; - break; - case RTL838X_TEMPLATE_FIELD_DMAC0: - data = pr->dmac[4]; - data = (data << 8) | pr->dmac[5]; - data_m = pr->dmac_m[4]; - data_m = (data_m << 8) | pr->dmac_m[5]; - break; - case RTL838X_TEMPLATE_FIELD_DMAC1: - data = pr->dmac[2]; - data = (data << 8) | pr->dmac[3]; - data_m = pr->dmac_m[2]; - data_m = (data_m << 8) | pr->dmac_m[3]; - break; - case RTL838X_TEMPLATE_FIELD_DMAC2: - data = pr->dmac[0]; - data = (data << 8) | pr->dmac[1]; - data_m = pr->dmac_m[0]; - data_m = (data_m << 8) | pr->dmac_m[1]; - break; - case RTL838X_TEMPLATE_FIELD_ETHERTYPE: - data = pr->ethertype; - data_m = pr->ethertype_m; - break; - case RTL838X_TEMPLATE_FIELD_ITAG: - data = pr->itag; - data_m = pr->itag_m; - break; - case RTL838X_TEMPLATE_FIELD_RANGE_CHK: - data = pr->field_range_check; - data_m = pr->field_range_check_m; - break; - case RTL838X_TEMPLATE_FIELD_SIP0: - if (pr->is_ipv6) { - data = pr->sip6.s6_addr16[7]; - data_m = pr->sip6_m.s6_addr16[7]; - } else { - data = pr->sip; - data_m = pr->sip_m; - } - break; - case RTL838X_TEMPLATE_FIELD_SIP1: - if (pr->is_ipv6) { - data = pr->sip6.s6_addr16[6]; - data_m = pr->sip6_m.s6_addr16[6]; - } else { - data = pr->sip >> 16; - data_m = pr->sip_m >> 16; - } - break; - case RTL838X_TEMPLATE_FIELD_SIP2: - case RTL838X_TEMPLATE_FIELD_SIP3: - case RTL838X_TEMPLATE_FIELD_SIP4: - case RTL838X_TEMPLATE_FIELD_SIP5: - case RTL838X_TEMPLATE_FIELD_SIP6: - case RTL838X_TEMPLATE_FIELD_SIP7: - data = pr->sip6.s6_addr16[5 - (field_type - RTL838X_TEMPLATE_FIELD_SIP2)]; - data_m = pr->sip6_m.s6_addr16[5 - (field_type - RTL838X_TEMPLATE_FIELD_SIP2)]; - break; - case RTL838X_TEMPLATE_FIELD_DIP0: - if (pr->is_ipv6) { - data = pr->dip6.s6_addr16[7]; - data_m = pr->dip6_m.s6_addr16[7]; - } else { - data = pr->dip; - data_m = pr->dip_m; - } - break; - case RTL838X_TEMPLATE_FIELD_DIP1: - if (pr->is_ipv6) { - data = pr->dip6.s6_addr16[6]; - data_m = pr->dip6_m.s6_addr16[6]; - } else { - data = pr->dip >> 16; - data_m = pr->dip_m >> 16; - } - break; - case RTL838X_TEMPLATE_FIELD_DIP2: - case RTL838X_TEMPLATE_FIELD_DIP3: - case RTL838X_TEMPLATE_FIELD_DIP4: - case RTL838X_TEMPLATE_FIELD_DIP5: - case RTL838X_TEMPLATE_FIELD_DIP6: - case RTL838X_TEMPLATE_FIELD_DIP7: - data = pr->dip6.s6_addr16[5 - (field_type - RTL838X_TEMPLATE_FIELD_DIP2)]; - data_m = pr->dip6_m.s6_addr16[5 - (field_type - RTL838X_TEMPLATE_FIELD_DIP2)]; - break; - case RTL838X_TEMPLATE_FIELD_IP_TOS_PROTO: - data = pr->tos_proto; - data_m = pr->tos_proto_m; - break; - case RTL838X_TEMPLATE_FIELD_L4_SPORT: - data = pr->sport; - data_m = pr->sport_m; - break; - case RTL838X_TEMPLATE_FIELD_L4_DPORT: - data = pr->dport; - data_m = pr->dport_m; - break; - case RTL838X_TEMPLATE_FIELD_ICMP_IGMP: - data = pr->icmp_igmp; - data_m = pr->icmp_igmp_m; - break; - default: - pr_debug("%s: unknown field %d\n", __func__, field_type); - continue; - } - if (!(i % 2)) { - r[5 - i / 2] = data; - r[12 - i / 2] = data_m; - } else { - r[5 - i / 2] |= ((u32)data) << 16; - r[12 - i / 2] |= ((u32)data_m) << 16; - } - } -} - -/* Creates the intermediate representation of the templated match-fields of the - * PIE rule in the pie_rule structure by reading the raw data fields in the - * raw register space r[]. - * The register space configuration size is identical for the RTL8380/90 and RTL9300, - * however the RTL9310 has 2 more registers / fields and the physical field-ids - */ -static void rtl838x_read_pie_templated(u32 r[], struct pie_rule *pr, enum rtl838x_template_field_id t[]) -{ - for (int i = 0; i < N_FIXED_FIELDS; i++) { - enum rtl838x_template_field_id field_type = t[i]; - u16 data, data_m; - - field_type = t[i]; - if (!(i % 2)) { - data = r[5 - i / 2]; - data_m = r[12 - i / 2]; - } else { - data = r[5 - i / 2] >> 16; - data_m = r[12 - i / 2] >> 16; - } - - switch (field_type) { - case RTL838X_TEMPLATE_FIELD_SPM0: - pr->spm = (pr->spn << 16) | data; - pr->spm_m = (pr->spn << 16) | data_m; - break; - case RTL838X_TEMPLATE_FIELD_SPM1: - pr->spm = data; - pr->spm_m = data_m; - break; - case RTL838X_TEMPLATE_FIELD_OTAG: - pr->otag = data; - pr->otag_m = data_m; - break; - case RTL838X_TEMPLATE_FIELD_SMAC0: - pr->smac[4] = data >> 8; - pr->smac[5] = data; - pr->smac_m[4] = data >> 8; - pr->smac_m[5] = data; - break; - case RTL838X_TEMPLATE_FIELD_SMAC1: - pr->smac[2] = data >> 8; - pr->smac[3] = data; - pr->smac_m[2] = data >> 8; - pr->smac_m[3] = data; - break; - case RTL838X_TEMPLATE_FIELD_SMAC2: - pr->smac[0] = data >> 8; - pr->smac[1] = data; - pr->smac_m[0] = data >> 8; - pr->smac_m[1] = data; - break; - case RTL838X_TEMPLATE_FIELD_DMAC0: - pr->dmac[4] = data >> 8; - pr->dmac[5] = data; - pr->dmac_m[4] = data >> 8; - pr->dmac_m[5] = data; - break; - case RTL838X_TEMPLATE_FIELD_DMAC1: - pr->dmac[2] = data >> 8; - pr->dmac[3] = data; - pr->dmac_m[2] = data >> 8; - pr->dmac_m[3] = data; - break; - case RTL838X_TEMPLATE_FIELD_DMAC2: - pr->dmac[0] = data >> 8; - pr->dmac[1] = data; - pr->dmac_m[0] = data >> 8; - pr->dmac_m[1] = data; - break; - case RTL838X_TEMPLATE_FIELD_ETHERTYPE: - pr->ethertype = data; - pr->ethertype_m = data_m; - break; - case RTL838X_TEMPLATE_FIELD_ITAG: - pr->itag = data; - pr->itag_m = data_m; - break; - case RTL838X_TEMPLATE_FIELD_RANGE_CHK: - pr->field_range_check = data; - pr->field_range_check_m = data_m; - break; - case RTL838X_TEMPLATE_FIELD_SIP0: - pr->sip = data; - pr->sip_m = data_m; - break; - case RTL838X_TEMPLATE_FIELD_SIP1: - pr->sip = (pr->sip << 16) | data; - pr->sip_m = (pr->sip << 16) | data_m; - break; - case RTL838X_TEMPLATE_FIELD_SIP2: - pr->is_ipv6 = true; - /* Make use of limitiations on the position of the match values */ - ipv6_addr_set(&pr->sip6, pr->sip, r[5 - i / 2], - r[4 - i / 2], r[3 - i / 2]); - ipv6_addr_set(&pr->sip6_m, pr->sip_m, r[5 - i / 2], - r[4 - i / 2], r[3 - i / 2]); - case RTL838X_TEMPLATE_FIELD_SIP3: - case RTL838X_TEMPLATE_FIELD_SIP4: - case RTL838X_TEMPLATE_FIELD_SIP5: - case RTL838X_TEMPLATE_FIELD_SIP6: - case RTL838X_TEMPLATE_FIELD_SIP7: - break; - case RTL838X_TEMPLATE_FIELD_DIP0: - pr->dip = data; - pr->dip_m = data_m; - break; - case RTL838X_TEMPLATE_FIELD_DIP1: - pr->dip = (pr->dip << 16) | data; - pr->dip_m = (pr->dip << 16) | data_m; - break; - case RTL838X_TEMPLATE_FIELD_DIP2: - pr->is_ipv6 = true; - ipv6_addr_set(&pr->dip6, pr->dip, r[5 - i / 2], - r[4 - i / 2], r[3 - i / 2]); - ipv6_addr_set(&pr->dip6_m, pr->dip_m, r[5 - i / 2], - r[4 - i / 2], r[3 - i / 2]); - case RTL838X_TEMPLATE_FIELD_DIP3: - case RTL838X_TEMPLATE_FIELD_DIP4: - case RTL838X_TEMPLATE_FIELD_DIP5: - case RTL838X_TEMPLATE_FIELD_DIP6: - case RTL838X_TEMPLATE_FIELD_DIP7: - break; - case RTL838X_TEMPLATE_FIELD_IP_TOS_PROTO: - pr->tos_proto = data; - pr->tos_proto_m = data_m; - break; - case RTL838X_TEMPLATE_FIELD_L4_SPORT: - pr->sport = data; - pr->sport_m = data_m; - break; - case RTL838X_TEMPLATE_FIELD_L4_DPORT: - pr->dport = data; - pr->dport_m = data_m; - break; - case RTL838X_TEMPLATE_FIELD_ICMP_IGMP: - pr->icmp_igmp = data; - pr->icmp_igmp_m = data_m; - break; - default: - pr_debug("%s: unknown field %d\n", __func__, field_type); - } - } -} - -static void rtl838x_read_pie_fixed_fields(u32 r[], struct pie_rule *pr) -{ - pr->spmmask_fix = (r[6] >> 22) & 0x3; - pr->spn = (r[6] >> 16) & 0x3f; - pr->mgnt_vlan = (r[6] >> 15) & 1; - pr->dmac_hit_sw = (r[6] >> 14) & 1; - pr->not_first_frag = (r[6] >> 13) & 1; - pr->frame_type_l4 = (r[6] >> 10) & 7; - pr->frame_type = (r[6] >> 8) & 3; - pr->otag_fmt = (r[6] >> 7) & 1; - pr->itag_fmt = (r[6] >> 6) & 1; - pr->otag_exist = (r[6] >> 5) & 1; - pr->itag_exist = (r[6] >> 4) & 1; - pr->frame_type_l2 = (r[6] >> 2) & 3; - pr->tid = r[6] & 3; - - pr->spmmask_fix_m = (r[13] >> 22) & 0x3; - pr->spn_m = (r[13] >> 16) & 0x3f; - pr->mgnt_vlan_m = (r[13] >> 15) & 1; - pr->dmac_hit_sw_m = (r[13] >> 14) & 1; - pr->not_first_frag_m = (r[13] >> 13) & 1; - pr->frame_type_l4_m = (r[13] >> 10) & 7; - pr->frame_type_m = (r[13] >> 8) & 3; - pr->otag_fmt_m = (r[13] >> 7) & 1; - pr->itag_fmt_m = (r[13] >> 6) & 1; - pr->otag_exist_m = (r[13] >> 5) & 1; - pr->itag_exist_m = (r[13] >> 4) & 1; - pr->frame_type_l2_m = (r[13] >> 2) & 3; - pr->tid_m = r[13] & 3; - - pr->valid = r[14] & BIT(31); - pr->cond_not = r[14] & BIT(30); - pr->cond_and1 = r[14] & BIT(29); - pr->cond_and2 = r[14] & BIT(28); - pr->ivalid = r[14] & BIT(27); - - pr->drop = (r[17] >> 14) & 3; - pr->fwd_sel = r[17] & BIT(13); - pr->ovid_sel = r[17] & BIT(12); - pr->ivid_sel = r[17] & BIT(11); - pr->flt_sel = r[17] & BIT(10); - pr->log_sel = r[17] & BIT(9); - pr->rmk_sel = r[17] & BIT(8); - pr->meter_sel = r[17] & BIT(7); - pr->tagst_sel = r[17] & BIT(6); - pr->mir_sel = r[17] & BIT(5); - pr->nopri_sel = r[17] & BIT(4); - pr->cpupri_sel = r[17] & BIT(3); - pr->otpid_sel = r[17] & BIT(2); - pr->itpid_sel = r[17] & BIT(1); - pr->shaper_sel = r[17] & BIT(0); -} - -static void rtl838x_write_pie_fixed_fields(u32 r[], struct pie_rule *pr) -{ - r[6] = ((u32)(pr->spmmask_fix & 0x3)) << 22; - r[6] |= ((u32)(pr->spn & 0x3f)) << 16; - r[6] |= pr->mgnt_vlan ? BIT(15) : 0; - r[6] |= pr->dmac_hit_sw ? BIT(14) : 0; - r[6] |= pr->not_first_frag ? BIT(13) : 0; - r[6] |= ((u32)(pr->frame_type_l4 & 0x7)) << 10; - r[6] |= ((u32)(pr->frame_type & 0x3)) << 8; - r[6] |= pr->otag_fmt ? BIT(7) : 0; - r[6] |= pr->itag_fmt ? BIT(6) : 0; - r[6] |= pr->otag_exist ? BIT(5) : 0; - r[6] |= pr->itag_exist ? BIT(4) : 0; - r[6] |= ((u32)(pr->frame_type_l2 & 0x3)) << 2; - r[6] |= ((u32)(pr->tid & 0x3)); - - r[13] = ((u32)(pr->spmmask_fix_m & 0x3)) << 22; - r[13] |= ((u32)(pr->spn_m & 0x3f)) << 16; - r[13] |= pr->mgnt_vlan_m ? BIT(15) : 0; - r[13] |= pr->dmac_hit_sw_m ? BIT(14) : 0; - r[13] |= pr->not_first_frag_m ? BIT(13) : 0; - r[13] |= ((u32)(pr->frame_type_l4_m & 0x7)) << 10; - r[13] |= ((u32)(pr->frame_type_m & 0x3)) << 8; - r[13] |= pr->otag_fmt_m ? BIT(7) : 0; - r[13] |= pr->itag_fmt_m ? BIT(6) : 0; - r[13] |= pr->otag_exist_m ? BIT(5) : 0; - r[13] |= pr->itag_exist_m ? BIT(4) : 0; - r[13] |= ((u32)(pr->frame_type_l2_m & 0x3)) << 2; - r[13] |= ((u32)(pr->tid_m & 0x3)); - - r[14] = pr->valid ? BIT(31) : 0; - r[14] |= pr->cond_not ? BIT(30) : 0; - r[14] |= pr->cond_and1 ? BIT(29) : 0; - r[14] |= pr->cond_and2 ? BIT(28) : 0; - r[14] |= pr->ivalid ? BIT(27) : 0; - - if (pr->drop) - r[17] = 0x1 << 14; /* Standard drop action */ - else - r[17] = 0; - r[17] |= pr->fwd_sel ? BIT(13) : 0; - r[17] |= pr->ovid_sel ? BIT(12) : 0; - r[17] |= pr->ivid_sel ? BIT(11) : 0; - r[17] |= pr->flt_sel ? BIT(10) : 0; - r[17] |= pr->log_sel ? BIT(9) : 0; - r[17] |= pr->rmk_sel ? BIT(8) : 0; - r[17] |= pr->meter_sel ? BIT(7) : 0; - r[17] |= pr->tagst_sel ? BIT(6) : 0; - r[17] |= pr->mir_sel ? BIT(5) : 0; - r[17] |= pr->nopri_sel ? BIT(4) : 0; - r[17] |= pr->cpupri_sel ? BIT(3) : 0; - r[17] |= pr->otpid_sel ? BIT(2) : 0; - r[17] |= pr->itpid_sel ? BIT(1) : 0; - r[17] |= pr->shaper_sel ? BIT(0) : 0; -} - -static int rtl838x_write_pie_action(u32 r[], struct pie_rule *pr) -{ - u16 *aif = (u16 *)&r[17]; - u16 data; - int fields_used = 0; - - aif--; - - pr_debug("%s, at %08x\n", __func__, (u32)aif); - /* Multiple actions can be linked to a match of a PIE rule, - * they have different precedence depending on their type and this precedence - * defines which Action Information Field (0-4) in the IACL table stores - * the additional data of the action (like e.g. the port number a packet is - * forwarded to) - */ - /* TODO: count bits in selectors to limit to a maximum number of actions */ - if (pr->fwd_sel) { /* Forwarding action */ - data = pr->fwd_act << 13; - data |= pr->fwd_data; - data |= pr->bypass_all ? BIT(12) : 0; - data |= pr->bypass_ibc_sc ? BIT(11) : 0; - data |= pr->bypass_igr_stp ? BIT(10) : 0; - *aif-- = data; - fields_used++; - } - - if (pr->ovid_sel) { /* Outer VID action */ - data = (pr->ovid_act & 0x3) << 12; - data |= pr->ovid_data; - *aif-- = data; - fields_used++; - } - - if (pr->ivid_sel) { /* Inner VID action */ - data = (pr->ivid_act & 0x3) << 12; - data |= pr->ivid_data; - *aif-- = data; - fields_used++; - } - - if (pr->flt_sel) { /* Filter action */ - *aif-- = pr->flt_data; - fields_used++; - } - - if (pr->log_sel) { /* Log action */ - if (fields_used >= 4) - return -1; - *aif-- = pr->log_data; - fields_used++; - } - - if (pr->rmk_sel) { /* Remark action */ - if (fields_used >= 4) - return -1; - *aif-- = pr->rmk_data; - fields_used++; - } - - if (pr->meter_sel) { /* Meter action */ - if (fields_used >= 4) - return -1; - *aif-- = pr->meter_data; - fields_used++; - } - - if (pr->tagst_sel) { /* Egress Tag Status action */ - if (fields_used >= 4) - return -1; - *aif-- = pr->tagst_data; - fields_used++; - } - - if (pr->mir_sel) { /* Mirror action */ - if (fields_used >= 4) - return -1; - *aif-- = pr->mir_data; - fields_used++; - } - - if (pr->nopri_sel) { /* Normal Priority action */ - if (fields_used >= 4) - return -1; - *aif-- = pr->nopri_data; - fields_used++; - } - - if (pr->cpupri_sel) { /* CPU Priority action */ - if (fields_used >= 4) - return -1; - *aif-- = pr->nopri_data; - fields_used++; - } - - if (pr->otpid_sel) { /* OTPID action */ - if (fields_used >= 4) - return -1; - *aif-- = pr->otpid_data; - fields_used++; - } - - if (pr->itpid_sel) { /* ITPID action */ - if (fields_used >= 4) - return -1; - *aif-- = pr->itpid_data; - fields_used++; - } - - if (pr->shaper_sel) { /* Traffic shaper action */ - if (fields_used >= 4) - return -1; - *aif-- = pr->shaper_data; - fields_used++; - } - - return 0; -} - -static void rtl838x_read_pie_action(u32 r[], struct pie_rule *pr) -{ - u16 *aif = (u16 *)&r[17]; - - aif--; - - pr_debug("%s, at %08x\n", __func__, (u32)aif); - if (pr->drop) - pr_debug("%s: Action Drop: %d", __func__, pr->drop); - - if (pr->fwd_sel) { /* Forwarding action */ - pr->fwd_act = *aif >> 13; - pr->fwd_data = *aif--; - pr->bypass_all = pr->fwd_data & BIT(12); - pr->bypass_ibc_sc = pr->fwd_data & BIT(11); - pr->bypass_igr_stp = pr->fwd_data & BIT(10); - if (pr->bypass_all || pr->bypass_ibc_sc || pr->bypass_igr_stp) - pr->bypass_sel = true; - } - if (pr->ovid_sel) /* Outer VID action */ - pr->ovid_data = *aif--; - if (pr->ivid_sel) /* Inner VID action */ - pr->ivid_data = *aif--; - if (pr->flt_sel) /* Filter action */ - pr->flt_data = *aif--; - if (pr->log_sel) /* Log action */ - pr->log_data = *aif--; - if (pr->rmk_sel) /* Remark action */ - pr->rmk_data = *aif--; - if (pr->meter_sel) /* Meter action */ - pr->meter_data = *aif--; - if (pr->tagst_sel) /* Egress Tag Status action */ - pr->tagst_data = *aif--; - if (pr->mir_sel) /* Mirror action */ - pr->mir_data = *aif--; - if (pr->nopri_sel) /* Normal Priority action */ - pr->nopri_data = *aif--; - if (pr->cpupri_sel) /* CPU Priority action */ - pr->nopri_data = *aif--; - if (pr->otpid_sel) /* OTPID action */ - pr->otpid_data = *aif--; - if (pr->itpid_sel) /* ITPID action */ - pr->itpid_data = *aif--; - if (pr->shaper_sel) /* Traffic shaper action */ - pr->shaper_data = *aif--; -} - -static void rtl838x_pie_rule_dump_raw(u32 r[]) -{ - pr_debug("Raw IACL table entry:\n"); - pr_debug("Match : %08x %08x %08x %08x %08x %08x\n", r[0], r[1], r[2], r[3], r[4], r[5]); - pr_debug("Fixed : %08x\n", r[6]); - pr_debug("Match M: %08x %08x %08x %08x %08x %08x\n", r[7], r[8], r[9], r[10], r[11], r[12]); - pr_debug("Fixed M: %08x\n", r[13]); - pr_debug("AIF : %08x %08x %08x\n", r[14], r[15], r[16]); - pr_debug("Sel : %08x\n", r[17]); -} - -// Currently not used -// static void rtl838x_pie_rule_dump(struct pie_rule *pr) -// { -// pr_debug("Drop: %d, fwd: %d, ovid: %d, ivid: %d, flt: %d, log: %d, rmk: %d, meter: %d tagst: %d, mir: %d, nopri: %d, cpupri: %d, otpid: %d, itpid: %d, shape: %d\n", -// pr->drop, pr->fwd_sel, pr->ovid_sel, pr->ivid_sel, pr->flt_sel, pr->log_sel, pr->rmk_sel, pr->log_sel, pr->tagst_sel, pr->mir_sel, pr->nopri_sel, -// pr->cpupri_sel, pr->otpid_sel, pr->itpid_sel, pr->shaper_sel); -// if (pr->fwd_sel) -// pr_debug("FWD: %08x\n", pr->fwd_data); -// pr_debug("TID: %x, %x\n", pr->tid, pr->tid_m); -// } - -static int rtl838x_pie_rule_read(struct rtl838x_switch_priv *priv, int idx, struct pie_rule *pr) -{ - int tbl = otto_table_acquire(RTL8380_TBL_IACL); - u32 r[18]; - int block = idx / PIE_BLOCK_SIZE; - u32 t_select = sw_r32(RTL838X_ACL_BLK_TMPLTE_CTRL(block)); - - memset(pr, 0, sizeof(*pr)); - __otto_table_read(tbl, idx, &r); - - otto_table_release(tbl); - - rtl838x_read_pie_fixed_fields(r, pr); - if (!pr->valid) - return 0; - - pr_debug("%s: template_selectors %08x, tid: %d\n", __func__, t_select, pr->tid); - rtl838x_pie_rule_dump_raw(r); - - rtl838x_read_pie_templated(r, pr, rtl838x_fixed_templates[(t_select >> (pr->tid * 3)) & 0x7]); - - rtl838x_read_pie_action(r, pr); - - return 0; -} - -static int rtl838x_pie_rule_write(struct rtl838x_switch_priv *priv, int idx, struct pie_rule *pr) -{ - int tbl = otto_table_acquire(RTL8380_TBL_IACL); - u32 r[18]; - int err; - int block = idx / PIE_BLOCK_SIZE; - u32 t_select = sw_r32(RTL838X_ACL_BLK_TMPLTE_CTRL(block)); - - pr_debug("%s: %d, t_select: %08x\n", __func__, idx, t_select); - - for (int i = 0; i < 18; i++) - r[i] = 0; - - if (!pr->valid) { - err = -EINVAL; - pr_err("Rule invalid\n"); - goto errout; - } - - rtl838x_write_pie_fixed_fields(r, pr); - - pr_debug("%s: template %d\n", __func__, (t_select >> (pr->tid * 3)) & 0x7); - rtl838x_write_pie_templated(r, pr, rtl838x_fixed_templates[(t_select >> (pr->tid * 3)) & 0x7]); - - err = rtl838x_write_pie_action(r, pr); - if (err) { - pr_err("Rule actions too complex\n"); - goto errout; - } - -/* rtl838x_pie_rule_dump_raw(r); */ - - __otto_table_write(tbl, idx, &r); - otto_table_release(tbl); - - return err; - -errout: - /* Leave no half-built rule behind: commit an empty entry. The write - * used to go out with the data registers untouched, which committed - * whatever the previous table access had left in them. - */ - memset(r, 0, sizeof(r)); - __otto_table_write(tbl, idx, &r); - otto_table_release(tbl); - - return err; -} - -static bool rtl838x_pie_templ_has(int t, enum rtl838x_template_field_id field_type) -{ - enum rtl838x_template_field_id ft; - - for (int i = 0; i < N_FIXED_FIELDS; i++) { - ft = rtl838x_fixed_templates[t][i]; - if (field_type == ft) - return true; - } - - return false; -} - -static int rtl838x_pie_verify_template(struct rtl838x_switch_priv *priv, - struct pie_rule *pr, int t, int block) -{ - int i; - - if (!pr->is_ipv6 && pr->sip_m && !rtl838x_pie_templ_has(t, RTL838X_TEMPLATE_FIELD_SIP0)) - return -1; - - if (!pr->is_ipv6 && pr->dip_m && !rtl838x_pie_templ_has(t, RTL838X_TEMPLATE_FIELD_DIP0)) - return -1; - - if (pr->is_ipv6) { - if ((pr->sip6_m.s6_addr32[0] || - pr->sip6_m.s6_addr32[1] || - pr->sip6_m.s6_addr32[2] || - pr->sip6_m.s6_addr32[3]) && - !rtl838x_pie_templ_has(t, RTL838X_TEMPLATE_FIELD_SIP2)) - return -1; - if ((pr->dip6_m.s6_addr32[0] || - pr->dip6_m.s6_addr32[1] || - pr->dip6_m.s6_addr32[2] || - pr->dip6_m.s6_addr32[3]) && - !rtl838x_pie_templ_has(t, RTL838X_TEMPLATE_FIELD_DIP2)) - return -1; - } - - if (ether_addr_to_u64(pr->smac_m) && !rtl838x_pie_templ_has(t, RTL838X_TEMPLATE_FIELD_SMAC0)) - return -1; - - if (ether_addr_to_u64(pr->dmac_m) && !rtl838x_pie_templ_has(t, RTL838X_TEMPLATE_FIELD_DMAC0)) - return -1; - - if (pr->itag_m && !rtl838x_pie_templ_has(t, RTL838X_TEMPLATE_FIELD_ITAG)) - return -1; - - if (pr->sport_m && !rtl838x_pie_templ_has(t, RTL838X_TEMPLATE_FIELD_L4_SPORT)) - return -1; - - if (pr->dport_m && !rtl838x_pie_templ_has(t, RTL838X_TEMPLATE_FIELD_L4_DPORT)) - return -1; - - /* TODO: Check more */ - - i = find_first_zero_bit(&priv->pie_use_bm[block * 4], PIE_BLOCK_SIZE); - - if (i >= PIE_BLOCK_SIZE) - return -1; - - return i + PIE_BLOCK_SIZE * block; -} - -static int rtl838x_pie_rule_add(struct rtl838x_switch_priv *priv, struct pie_rule *pr) -{ - int idx, block, j; - - pr_debug("In %s\n", __func__); - - mutex_lock(&priv->pie_mutex); - - for (block = 0; block < priv->r->n_pie_blocks; block++) { - for (j = 0; j < 3; j++) { - int t = (sw_r32(RTL838X_ACL_BLK_TMPLTE_CTRL(block)) >> (j * 3)) & 0x7; - - pr_debug("Testing block %d, template %d, template id %d\n", block, j, t); - idx = rtl838x_pie_verify_template(priv, pr, t, block); - if (idx >= 0) - break; - } - if (j < 3) - break; - } - - if (block >= priv->r->n_pie_blocks) { - mutex_unlock(&priv->pie_mutex); - return -EOPNOTSUPP; - } - - pr_debug("Using block: %d, index %d, template-id %d\n", block, idx, j); - set_bit(idx, priv->pie_use_bm); - - pr->valid = true; - pr->tid = j; /* Mapped to template number */ - pr->tid_m = 0x3; - pr->id = idx; - - rtl838x_pie_lookup_enable(priv, idx); - rtl838x_pie_rule_write(priv, idx, pr); - - mutex_unlock(&priv->pie_mutex); - - return 0; -} - -static void rtl838x_pie_rule_rm(struct rtl838x_switch_priv *priv, struct pie_rule *pr) -{ - int idx = pr->id; - - rtl838x_pie_rule_del(priv, idx, idx); - clear_bit(idx, priv->pie_use_bm); -} - -/* Initializes the Packet Inspection Engine: - * powers it up, enables default matching templates for all blocks - * and clears all rules possibly installed by u-boot - */ -static void rtl838x_pie_init(struct rtl838x_switch_priv *priv) -{ - u32 template_selectors; - - mutex_init(&priv->pie_mutex); - - /* Enable ACL lookup on all ports, including CPU_PORT */ - for (int i = 0; i <= priv->r->cpu_port; i++) - sw_w32(1, RTL838X_ACL_PORT_LOOKUP_CTRL(i)); - - /* Power on all PIE blocks */ - for (int i = 0; i < priv->r->n_pie_blocks; i++) - sw_w32_mask(0, BIT(i), RTL838X_ACL_BLK_PWR_CTRL); - - /* Include IPG in metering */ - sw_w32(1, RTL838X_METER_GLB_CTRL); - - /* Delete all present rules */ - rtl838x_pie_rule_del(priv, 0, priv->r->n_pie_blocks * PIE_BLOCK_SIZE - 1); - - /* Routing bypasses source port filter */ - sw_w32_mask(0, 1, RTL838X_DMY_REG27); - - /* Enable predefined templates 0, 1 and 2 for even blocks */ - template_selectors = 0 | (1 << 3) | (2 << 6); - for (int i = 0; i < 6; i += 2) - sw_w32(template_selectors, RTL838X_ACL_BLK_TMPLTE_CTRL(i)); - - /* Enable predefined templates 0, 3 and 4 (IPv6 support) for odd blocks */ - template_selectors = 0 | (3 << 3) | (4 << 6); - for (int i = 1; i < priv->r->n_pie_blocks; i += 2) - sw_w32(template_selectors, RTL838X_ACL_BLK_TMPLTE_CTRL(i)); - - /* Group each pair of physical blocks together to a logical block */ - sw_w32(0b10101010101, RTL838X_ACL_BLK_GROUP_CTRL); -} - static u32 rtl838x_packet_cntr_read(struct rtl838x_switch_priv *priv, int counter) { u32 buf[2]; diff --git a/target/linux/realtek/files-6.18/drivers/net/dsa/rtl83xx/rtl839x.c b/target/linux/realtek/files-6.18/drivers/net/dsa/rtl83xx/rtl839x.c index 7c4f55b3b31..2f40173b71f 100644 --- a/target/linux/realtek/files-6.18/drivers/net/dsa/rtl83xx/rtl839x.c +++ b/target/linux/realtek/files-6.18/drivers/net/dsa/rtl83xx/rtl839x.c @@ -4,106 +4,10 @@ #include #include "l3.h" +#include "pie.h" #include "rtl-otto.h" #include "vlan.h" -/* Definition of the RTL839X-specific template field IDs as used in the PIE */ -enum rtl839x_template_field_id { - RTL839X_TEMPLATE_FIELD_SPMMASK = 0, - RTL839X_TEMPLATE_FIELD_SPM0 = 1, /* Source portmask ports 0-15 */ - RTL839X_TEMPLATE_FIELD_SPM1 = 2, /* Source portmask ports 16-31 */ - RTL839X_TEMPLATE_FIELD_SPM2 = 3, /* Source portmask ports 32-47 */ - RTL839X_TEMPLATE_FIELD_SPM3 = 4, /* Source portmask ports 48-56 */ - RTL839X_TEMPLATE_FIELD_DMAC0 = 5, /* Destination MAC [15:0] */ - RTL839X_TEMPLATE_FIELD_DMAC1 = 6, /* Destination MAC [31:16] */ - RTL839X_TEMPLATE_FIELD_DMAC2 = 7, /* Destination MAC [47:32] */ - RTL839X_TEMPLATE_FIELD_SMAC0 = 8, /* Source MAC [15:0] */ - RTL839X_TEMPLATE_FIELD_SMAC1 = 9, /* Source MAC [31:16] */ - RTL839X_TEMPLATE_FIELD_SMAC2 = 10, /* Source MAC [47:32] */ - RTL839X_TEMPLATE_FIELD_ETHERTYPE = 11, /* Ethernet frame type field */ - /* Field-ID 12 is not used */ - RTL839X_TEMPLATE_FIELD_OTAG = 13, - RTL839X_TEMPLATE_FIELD_ITAG = 14, - RTL839X_TEMPLATE_FIELD_SIP0 = 15, - RTL839X_TEMPLATE_FIELD_SIP1 = 16, - RTL839X_TEMPLATE_FIELD_DIP0 = 17, - RTL839X_TEMPLATE_FIELD_DIP1 = 18, - RTL839X_TEMPLATE_FIELD_IP_TOS_PROTO = 19, - RTL839X_TEMPLATE_FIELD_IP_FLAG = 20, - RTL839X_TEMPLATE_FIELD_L4_SPORT = 21, - RTL839X_TEMPLATE_FIELD_L4_DPORT = 22, - RTL839X_TEMPLATE_FIELD_L34_HEADER = 23, - RTL839X_TEMPLATE_FIELD_ICMP_IGMP = 24, - RTL839X_TEMPLATE_FIELD_VID_RANG0 = 25, - RTL839X_TEMPLATE_FIELD_VID_RANG1 = 26, - RTL839X_TEMPLATE_FIELD_L4_PORT_RANG = 27, - RTL839X_TEMPLATE_FIELD_FIELD_SELECTOR_VALID = 28, - RTL839X_TEMPLATE_FIELD_FIELD_SELECTOR_0 = 29, - RTL839X_TEMPLATE_FIELD_FIELD_SELECTOR_1 = 30, - RTL839X_TEMPLATE_FIELD_FIELD_SELECTOR_2 = 31, - RTL839X_TEMPLATE_FIELD_FIELD_SELECTOR_3 = 32, - RTL839X_TEMPLATE_FIELD_FIELD_SELECTOR_4 = 33, - RTL839X_TEMPLATE_FIELD_FIELD_SELECTOR_5 = 34, - RTL839X_TEMPLATE_FIELD_SIP2 = 35, - RTL839X_TEMPLATE_FIELD_SIP3 = 36, - RTL839X_TEMPLATE_FIELD_SIP4 = 37, - RTL839X_TEMPLATE_FIELD_SIP5 = 38, - RTL839X_TEMPLATE_FIELD_SIP6 = 39, - RTL839X_TEMPLATE_FIELD_SIP7 = 40, - RTL839X_TEMPLATE_FIELD_OLABEL = 41, - RTL839X_TEMPLATE_FIELD_ILABEL = 42, - RTL839X_TEMPLATE_FIELD_OILABEL = 43, - RTL839X_TEMPLATE_FIELD_DPMMASK = 44, - RTL839X_TEMPLATE_FIELD_DPM0 = 45, - RTL839X_TEMPLATE_FIELD_DPM1 = 46, - RTL839X_TEMPLATE_FIELD_DPM2 = 47, - RTL839X_TEMPLATE_FIELD_DPM3 = 48, - RTL839X_TEMPLATE_FIELD_L2DPM0 = 49, - RTL839X_TEMPLATE_FIELD_L2DPM1 = 50, - RTL839X_TEMPLATE_FIELD_L2DPM2 = 51, - RTL839X_TEMPLATE_FIELD_L2DPM3 = 52, - RTL839X_TEMPLATE_FIELD_IVLAN = 53, - RTL839X_TEMPLATE_FIELD_OVLAN = 54, - RTL839X_TEMPLATE_FIELD_FWD_VID = 55, - RTL839X_TEMPLATE_FIELD_DIP2 = 56, - RTL839X_TEMPLATE_FIELD_DIP3 = 57, - RTL839X_TEMPLATE_FIELD_DIP4 = 58, - RTL839X_TEMPLATE_FIELD_DIP5 = 59, - RTL839X_TEMPLATE_FIELD_DIP6 = 60, - RTL839X_TEMPLATE_FIELD_DIP7 = 61, -}; - -/* Number of fixed templates predefined in the SoC */ -#define RTL839X_N_FIXED_TEMPLATES 5 -static enum rtl839x_template_field_id rtl839x_fixed_templates[RTL839X_N_FIXED_TEMPLATES][N_FIXED_FIELDS] = { - { - RTL839X_TEMPLATE_FIELD_SPM0, RTL839X_TEMPLATE_FIELD_SPM1, RTL839X_TEMPLATE_FIELD_ITAG, - RTL839X_TEMPLATE_FIELD_SMAC0, RTL839X_TEMPLATE_FIELD_SMAC1, RTL839X_TEMPLATE_FIELD_SMAC2, - RTL839X_TEMPLATE_FIELD_DMAC0, RTL839X_TEMPLATE_FIELD_DMAC1, RTL839X_TEMPLATE_FIELD_DMAC2, - RTL839X_TEMPLATE_FIELD_ETHERTYPE, RTL839X_TEMPLATE_FIELD_SPM2, RTL839X_TEMPLATE_FIELD_SPM3 - }, { - RTL839X_TEMPLATE_FIELD_SIP0, RTL839X_TEMPLATE_FIELD_SIP1, RTL839X_TEMPLATE_FIELD_DIP0, - RTL839X_TEMPLATE_FIELD_DIP1, RTL839X_TEMPLATE_FIELD_IP_TOS_PROTO, RTL839X_TEMPLATE_FIELD_L4_SPORT, - RTL839X_TEMPLATE_FIELD_L4_DPORT, RTL839X_TEMPLATE_FIELD_ICMP_IGMP, RTL839X_TEMPLATE_FIELD_SPM0, - RTL839X_TEMPLATE_FIELD_SPM1, RTL839X_TEMPLATE_FIELD_SPM2, RTL839X_TEMPLATE_FIELD_SPM3 - }, { - RTL839X_TEMPLATE_FIELD_DMAC0, RTL839X_TEMPLATE_FIELD_DMAC1, RTL839X_TEMPLATE_FIELD_DMAC2, - RTL839X_TEMPLATE_FIELD_ITAG, RTL839X_TEMPLATE_FIELD_ETHERTYPE, RTL839X_TEMPLATE_FIELD_IP_TOS_PROTO, - RTL839X_TEMPLATE_FIELD_L4_DPORT, RTL839X_TEMPLATE_FIELD_L4_SPORT, RTL839X_TEMPLATE_FIELD_SIP0, - RTL839X_TEMPLATE_FIELD_SIP1, RTL839X_TEMPLATE_FIELD_DIP0, RTL839X_TEMPLATE_FIELD_DIP1 - }, { - RTL839X_TEMPLATE_FIELD_DIP0, RTL839X_TEMPLATE_FIELD_DIP1, RTL839X_TEMPLATE_FIELD_DIP2, - RTL839X_TEMPLATE_FIELD_DIP3, RTL839X_TEMPLATE_FIELD_DIP4, RTL839X_TEMPLATE_FIELD_DIP5, - RTL839X_TEMPLATE_FIELD_DIP6, RTL839X_TEMPLATE_FIELD_DIP7, RTL839X_TEMPLATE_FIELD_L4_DPORT, - RTL839X_TEMPLATE_FIELD_L4_SPORT, RTL839X_TEMPLATE_FIELD_ICMP_IGMP, RTL839X_TEMPLATE_FIELD_IP_TOS_PROTO - }, { - RTL839X_TEMPLATE_FIELD_SIP0, RTL839X_TEMPLATE_FIELD_SIP1, RTL839X_TEMPLATE_FIELD_SIP2, - RTL839X_TEMPLATE_FIELD_SIP3, RTL839X_TEMPLATE_FIELD_SIP4, RTL839X_TEMPLATE_FIELD_SIP5, - RTL839X_TEMPLATE_FIELD_SIP6, RTL839X_TEMPLATE_FIELD_SIP7, RTL839X_TEMPLATE_FIELD_SPM0, - RTL839X_TEMPLATE_FIELD_SPM1, RTL839X_TEMPLATE_FIELD_SPM2, RTL839X_TEMPLATE_FIELD_SPM3 - }, -}; - const struct rtldsa_mib_list_item rtldsa_839x_mib_list[] = { MIB_LIST_ITEM("ifOutDiscards", MIB_ITEM(MIB_REG_STD, 0xd4, 1)), MIB_LIST_ITEM("dot1dTpPortInDiscards", MIB_ITEM(MIB_REG_STD, 0xd0, 1)), @@ -611,726 +515,6 @@ static void rtl839x_init_eee(struct rtl838x_switch_priv *priv, bool enable) priv->eee_enabled = enable; } -static void rtl839x_pie_lookup_enable(struct rtl838x_switch_priv *priv, int index) -{ - int block = index / PIE_BLOCK_SIZE; - - sw_w32_mask(0, BIT(block), RTL839X_ACL_BLK_LOOKUP_CTRL); -} - -/* Delete a range of Packet Inspection Engine rules */ -static int rtl839x_pie_rule_del(struct rtl838x_switch_priv *priv, int index_from, int index_to) -{ - u32 v = (index_from << 1) | (index_to << 13) | BIT(0); - - pr_debug("%s: from %d to %d\n", __func__, index_from, index_to); - mutex_lock(&priv->reg_mutex); - - /* Write from-to and execute bit into control register */ - sw_w32(v, RTL839X_ACL_CLR_CTRL); - - /* Wait until command has completed */ - do { - } while (sw_r32(RTL839X_ACL_CLR_CTRL) & BIT(0)); - - mutex_unlock(&priv->reg_mutex); - - return 0; -} - -/* Reads the intermediate representation of the templated match-fields of the - * PIE rule in the pie_rule structure and fills in the raw data fields in the - * raw register space r[]. - * The register space configuration size is identical for the RTL8380/90 and RTL9300, - * however the RTL9310 has 2 more registers / fields and the physical field-ids are different - * on all SoCs - * On the RTL8390 the template mask registers are not word-aligned! - */ -static void rtl839x_write_pie_templated(u32 r[], struct pie_rule *pr, enum rtl839x_template_field_id t[]) -{ - for (int i = 0; i < N_FIXED_FIELDS; i++) { - enum rtl839x_template_field_id field_type = t[i]; - u16 data = 0, data_m = 0; - - switch (field_type) { - case RTL839X_TEMPLATE_FIELD_SPM0: - data = pr->spm; - data_m = pr->spm_m; - break; - case RTL839X_TEMPLATE_FIELD_SPM1: - data = pr->spm >> 16; - data_m = pr->spm_m >> 16; - break; - case RTL839X_TEMPLATE_FIELD_SPM2: - data = pr->spm >> 32; - data_m = pr->spm_m >> 32; - break; - case RTL839X_TEMPLATE_FIELD_SPM3: - data = pr->spm >> 48; - data_m = pr->spm_m >> 48; - break; - case RTL839X_TEMPLATE_FIELD_OTAG: - data = pr->otag; - data_m = pr->otag_m; - break; - case RTL839X_TEMPLATE_FIELD_SMAC0: - data = pr->smac[4]; - data = (data << 8) | pr->smac[5]; - data_m = pr->smac_m[4]; - data_m = (data_m << 8) | pr->smac_m[5]; - break; - case RTL839X_TEMPLATE_FIELD_SMAC1: - data = pr->smac[2]; - data = (data << 8) | pr->smac[3]; - data_m = pr->smac_m[2]; - data_m = (data_m << 8) | pr->smac_m[3]; - break; - case RTL839X_TEMPLATE_FIELD_SMAC2: - data = pr->smac[0]; - data = (data << 8) | pr->smac[1]; - data_m = pr->smac_m[0]; - data_m = (data_m << 8) | pr->smac_m[1]; - break; - case RTL839X_TEMPLATE_FIELD_DMAC0: - data = pr->dmac[4]; - data = (data << 8) | pr->dmac[5]; - data_m = pr->dmac_m[4]; - data_m = (data_m << 8) | pr->dmac_m[5]; - break; - case RTL839X_TEMPLATE_FIELD_DMAC1: - data = pr->dmac[2]; - data = (data << 8) | pr->dmac[3]; - data_m = pr->dmac_m[2]; - data_m = (data_m << 8) | pr->dmac_m[3]; - break; - case RTL839X_TEMPLATE_FIELD_DMAC2: - data = pr->dmac[0]; - data = (data << 8) | pr->dmac[1]; - data_m = pr->dmac_m[0]; - data_m = (data_m << 8) | pr->dmac_m[1]; - break; - case RTL839X_TEMPLATE_FIELD_ETHERTYPE: - data = pr->ethertype; - data_m = pr->ethertype_m; - break; - case RTL839X_TEMPLATE_FIELD_ITAG: - data = pr->itag; - data_m = pr->itag_m; - break; - case RTL839X_TEMPLATE_FIELD_SIP0: - if (pr->is_ipv6) { - data = pr->sip6.s6_addr16[7]; - data_m = pr->sip6_m.s6_addr16[7]; - } else { - data = pr->sip; - data_m = pr->sip_m; - } - break; - case RTL839X_TEMPLATE_FIELD_SIP1: - if (pr->is_ipv6) { - data = pr->sip6.s6_addr16[6]; - data_m = pr->sip6_m.s6_addr16[6]; - } else { - data = pr->sip >> 16; - data_m = pr->sip_m >> 16; - } - break; - case RTL839X_TEMPLATE_FIELD_SIP2: - case RTL839X_TEMPLATE_FIELD_SIP3: - case RTL839X_TEMPLATE_FIELD_SIP4: - case RTL839X_TEMPLATE_FIELD_SIP5: - case RTL839X_TEMPLATE_FIELD_SIP6: - case RTL839X_TEMPLATE_FIELD_SIP7: - data = pr->sip6.s6_addr16[5 - (field_type - RTL839X_TEMPLATE_FIELD_SIP2)]; - data_m = pr->sip6_m.s6_addr16[5 - (field_type - RTL839X_TEMPLATE_FIELD_SIP2)]; - break; - case RTL839X_TEMPLATE_FIELD_DIP0: - if (pr->is_ipv6) { - data = pr->dip6.s6_addr16[7]; - data_m = pr->dip6_m.s6_addr16[7]; - } else { - data = pr->dip; - data_m = pr->dip_m; - } - break; - case RTL839X_TEMPLATE_FIELD_DIP1: - if (pr->is_ipv6) { - data = pr->dip6.s6_addr16[6]; - data_m = pr->dip6_m.s6_addr16[6]; - } else { - data = pr->dip >> 16; - data_m = pr->dip_m >> 16; - } - break; - case RTL839X_TEMPLATE_FIELD_DIP2: - case RTL839X_TEMPLATE_FIELD_DIP3: - case RTL839X_TEMPLATE_FIELD_DIP4: - case RTL839X_TEMPLATE_FIELD_DIP5: - case RTL839X_TEMPLATE_FIELD_DIP6: - case RTL839X_TEMPLATE_FIELD_DIP7: - data = pr->dip6.s6_addr16[5 - (field_type - RTL839X_TEMPLATE_FIELD_DIP2)]; - data_m = pr->dip6_m.s6_addr16[5 - (field_type - RTL839X_TEMPLATE_FIELD_DIP2)]; - break; - case RTL839X_TEMPLATE_FIELD_IP_TOS_PROTO: - data = pr->tos_proto; - data_m = pr->tos_proto_m; - break; - case RTL839X_TEMPLATE_FIELD_L4_SPORT: - data = pr->sport; - data_m = pr->sport_m; - break; - case RTL839X_TEMPLATE_FIELD_L4_DPORT: - data = pr->dport; - data_m = pr->dport_m; - break; - case RTL839X_TEMPLATE_FIELD_ICMP_IGMP: - data = pr->icmp_igmp; - data_m = pr->icmp_igmp_m; - break; - default: - pr_debug("%s: unknown field %d\n", __func__, field_type); - } - - /* On the RTL8390, the mask fields are not word aligned! */ - if (!(i % 2)) { - r[5 - i / 2] = data; - r[12 - i / 2] |= ((u32)data_m << 8); - } else { - r[5 - i / 2] |= ((u32)data) << 16; - r[12 - i / 2] |= ((u32)data_m) << 24; - r[11 - i / 2] |= ((u32)data_m) >> 8; - } - } -} - -/* Creates the intermediate representation of the templated match-fields of the - * PIE rule in the pie_rule structure by reading the raw data fields in the - * raw register space r[]. - * The register space configuration size is identical for the RTL8380/90 and RTL9300, - * however the RTL9310 has 2 more registers / fields and the physical field-ids - * On the RTL8390 the template mask registers are not word-aligned! - */ -static void rtl839x_read_pie_templated(u32 r[], struct pie_rule *pr, enum rtl839x_template_field_id t[]) -{ - for (int i = 0; i < N_FIXED_FIELDS; i++) { - enum rtl839x_template_field_id field_type = t[i]; - u16 data, data_m; - - if (!(i % 2)) { - data = r[5 - i / 2]; - data_m = r[12 - i / 2]; - } else { - data = r[5 - i / 2] >> 16; - data_m = r[12 - i / 2] >> 16; - } - - switch (field_type) { - case RTL839X_TEMPLATE_FIELD_SPM0: - pr->spm = (pr->spn << 16) | data; - pr->spm_m = (pr->spn << 16) | data_m; - break; - case RTL839X_TEMPLATE_FIELD_SPM1: - pr->spm = data; - pr->spm_m = data_m; - break; - case RTL839X_TEMPLATE_FIELD_OTAG: - pr->otag = data; - pr->otag_m = data_m; - break; - case RTL839X_TEMPLATE_FIELD_SMAC0: - pr->smac[4] = data >> 8; - pr->smac[5] = data; - pr->smac_m[4] = data >> 8; - pr->smac_m[5] = data; - break; - case RTL839X_TEMPLATE_FIELD_SMAC1: - pr->smac[2] = data >> 8; - pr->smac[3] = data; - pr->smac_m[2] = data >> 8; - pr->smac_m[3] = data; - break; - case RTL839X_TEMPLATE_FIELD_SMAC2: - pr->smac[0] = data >> 8; - pr->smac[1] = data; - pr->smac_m[0] = data >> 8; - pr->smac_m[1] = data; - break; - case RTL839X_TEMPLATE_FIELD_DMAC0: - pr->dmac[4] = data >> 8; - pr->dmac[5] = data; - pr->dmac_m[4] = data >> 8; - pr->dmac_m[5] = data; - break; - case RTL839X_TEMPLATE_FIELD_DMAC1: - pr->dmac[2] = data >> 8; - pr->dmac[3] = data; - pr->dmac_m[2] = data >> 8; - pr->dmac_m[3] = data; - break; - case RTL839X_TEMPLATE_FIELD_DMAC2: - pr->dmac[0] = data >> 8; - pr->dmac[1] = data; - pr->dmac_m[0] = data >> 8; - pr->dmac_m[1] = data; - break; - case RTL839X_TEMPLATE_FIELD_ETHERTYPE: - pr->ethertype = data; - pr->ethertype_m = data_m; - break; - case RTL839X_TEMPLATE_FIELD_ITAG: - pr->itag = data; - pr->itag_m = data_m; - break; - case RTL839X_TEMPLATE_FIELD_SIP0: - pr->sip = data; - pr->sip_m = data_m; - break; - case RTL839X_TEMPLATE_FIELD_SIP1: - pr->sip = (pr->sip << 16) | data; - pr->sip_m = (pr->sip << 16) | data_m; - break; - case RTL839X_TEMPLATE_FIELD_SIP2: - pr->is_ipv6 = true; - /* Make use of limitiations on the position of the match values */ - ipv6_addr_set(&pr->sip6, pr->sip, r[5 - i / 2], - r[4 - i / 2], r[3 - i / 2]); - ipv6_addr_set(&pr->sip6_m, pr->sip_m, r[5 - i / 2], - r[4 - i / 2], r[3 - i / 2]); - case RTL839X_TEMPLATE_FIELD_SIP3: - case RTL839X_TEMPLATE_FIELD_SIP4: - case RTL839X_TEMPLATE_FIELD_SIP5: - case RTL839X_TEMPLATE_FIELD_SIP6: - case RTL839X_TEMPLATE_FIELD_SIP7: - break; - - case RTL839X_TEMPLATE_FIELD_DIP0: - pr->dip = data; - pr->dip_m = data_m; - break; - - case RTL839X_TEMPLATE_FIELD_DIP1: - pr->dip = (pr->dip << 16) | data; - pr->dip_m = (pr->dip << 16) | data_m; - break; - - case RTL839X_TEMPLATE_FIELD_DIP2: - pr->is_ipv6 = true; - ipv6_addr_set(&pr->dip6, pr->dip, r[5 - i / 2], - r[4 - i / 2], r[3 - i / 2]); - ipv6_addr_set(&pr->dip6_m, pr->dip_m, r[5 - i / 2], - r[4 - i / 2], r[3 - i / 2]); - case RTL839X_TEMPLATE_FIELD_DIP3: - case RTL839X_TEMPLATE_FIELD_DIP4: - case RTL839X_TEMPLATE_FIELD_DIP5: - case RTL839X_TEMPLATE_FIELD_DIP6: - case RTL839X_TEMPLATE_FIELD_DIP7: - break; - case RTL839X_TEMPLATE_FIELD_IP_TOS_PROTO: - pr->tos_proto = data; - pr->tos_proto_m = data_m; - break; - case RTL839X_TEMPLATE_FIELD_L4_SPORT: - pr->sport = data; - pr->sport_m = data_m; - break; - case RTL839X_TEMPLATE_FIELD_L4_DPORT: - pr->dport = data; - pr->dport_m = data_m; - break; - case RTL839X_TEMPLATE_FIELD_ICMP_IGMP: - pr->icmp_igmp = data; - pr->icmp_igmp_m = data_m; - break; - default: - pr_debug("%s: unknown field %d\n", __func__, field_type); - } - } -} - -static void rtl839x_read_pie_fixed_fields(u32 r[], struct pie_rule *pr) -{ - pr->spmmask_fix = (r[6] >> 30) & 0x3; - pr->spn = (r[6] >> 24) & 0x3f; - pr->mgnt_vlan = (r[6] >> 23) & 1; - pr->dmac_hit_sw = (r[6] >> 22) & 1; - pr->not_first_frag = (r[6] >> 21) & 1; - pr->frame_type_l4 = (r[6] >> 18) & 7; - pr->frame_type = (r[6] >> 16) & 3; - pr->otag_fmt = (r[6] >> 15) & 1; - pr->itag_fmt = (r[6] >> 14) & 1; - pr->otag_exist = (r[6] >> 13) & 1; - pr->itag_exist = (r[6] >> 12) & 1; - pr->frame_type_l2 = (r[6] >> 10) & 3; - pr->tid = (r[6] >> 8) & 3; - - pr->spmmask_fix_m = (r[12] >> 6) & 0x3; - pr->spn_m = r[12] & 0x3f; - pr->mgnt_vlan_m = (r[13] >> 31) & 1; - pr->dmac_hit_sw_m = (r[13] >> 30) & 1; - pr->not_first_frag_m = (r[13] >> 29) & 1; - pr->frame_type_l4_m = (r[13] >> 26) & 7; - pr->frame_type_m = (r[13] >> 24) & 3; - pr->otag_fmt_m = (r[13] >> 23) & 1; - pr->itag_fmt_m = (r[13] >> 22) & 1; - pr->otag_exist_m = (r[13] >> 21) & 1; - pr->itag_exist_m = (r[13] >> 20) & 1; - pr->frame_type_l2_m = (r[13] >> 18) & 3; - pr->tid_m = (r[13] >> 16) & 3; - - pr->valid = r[13] & BIT(15); - pr->cond_not = r[13] & BIT(14); - pr->cond_and1 = r[13] & BIT(13); - pr->cond_and2 = r[13] & BIT(12); -} - -static void rtl839x_write_pie_fixed_fields(u32 r[], struct pie_rule *pr) -{ - r[6] = ((u32)(pr->spmmask_fix & 0x3)) << 30; - r[6] |= ((u32)(pr->spn & 0x3f)) << 24; - r[6] |= pr->mgnt_vlan ? BIT(23) : 0; - r[6] |= pr->dmac_hit_sw ? BIT(22) : 0; - r[6] |= pr->not_first_frag ? BIT(21) : 0; - r[6] |= ((u32)(pr->frame_type_l4 & 0x7)) << 18; - r[6] |= ((u32)(pr->frame_type & 0x3)) << 16; - r[6] |= pr->otag_fmt ? BIT(15) : 0; - r[6] |= pr->itag_fmt ? BIT(14) : 0; - r[6] |= pr->otag_exist ? BIT(13) : 0; - r[6] |= pr->itag_exist ? BIT(12) : 0; - r[6] |= ((u32)(pr->frame_type_l2 & 0x3)) << 10; - r[6] |= ((u32)(pr->tid & 0x3)) << 8; - - r[12] |= ((u32)(pr->spmmask_fix_m & 0x3)) << 6; - r[12] |= (u32)(pr->spn_m & 0x3f); - r[13] |= pr->mgnt_vlan_m ? BIT(31) : 0; - r[13] |= pr->dmac_hit_sw_m ? BIT(30) : 0; - r[13] |= pr->not_first_frag_m ? BIT(29) : 0; - r[13] |= ((u32)(pr->frame_type_l4_m & 0x7)) << 26; - r[13] |= ((u32)(pr->frame_type_m & 0x3)) << 24; - r[13] |= pr->otag_fmt_m ? BIT(23) : 0; - r[13] |= pr->itag_fmt_m ? BIT(22) : 0; - r[13] |= pr->otag_exist_m ? BIT(21) : 0; - r[13] |= pr->itag_exist_m ? BIT(20) : 0; - r[13] |= ((u32)(pr->frame_type_l2_m & 0x3)) << 18; - r[13] |= ((u32)(pr->tid_m & 0x3)) << 16; - - r[13] |= pr->valid ? BIT(15) : 0; - r[13] |= pr->cond_not ? BIT(14) : 0; - r[13] |= pr->cond_and1 ? BIT(13) : 0; - r[13] |= pr->cond_and2 ? BIT(12) : 0; -} - -static void rtl839x_write_pie_action(u32 r[], struct pie_rule *pr) -{ - if (pr->drop) { - r[13] |= 0x9; /* Set ACT_MASK_FWD & FWD_ACT = DROP */ - r[13] |= BIT(3); - } else { - r[13] |= pr->fwd_sel ? BIT(3) : 0; - r[13] |= pr->fwd_act; - } - r[13] |= pr->bypass_sel ? BIT(11) : 0; - r[13] |= pr->mpls_sel ? BIT(10) : 0; - r[13] |= pr->nopri_sel ? BIT(9) : 0; - r[13] |= pr->ovid_sel ? BIT(8) : 0; - r[13] |= pr->ivid_sel ? BIT(7) : 0; - r[13] |= pr->meter_sel ? BIT(6) : 0; - r[13] |= pr->mir_sel ? BIT(5) : 0; - r[13] |= pr->log_sel ? BIT(4) : 0; - - r[14] |= ((u32)(pr->fwd_data & 0x3fff)) << 18; - r[14] |= pr->log_octets ? BIT(17) : 0; - r[14] |= ((u32)(pr->log_data & 0x7ff)) << 4; - r[14] |= (pr->mir_data & 0x3) << 3; - r[14] |= ((u32)(pr->meter_data >> 7)) & 0x7; - r[15] |= (u32)(pr->meter_data) << 26; - r[15] |= ((u32)(pr->ivid_act) << 23) & 0x3; - r[15] |= ((u32)(pr->ivid_data) << 9) & 0xfff; - r[15] |= ((u32)(pr->ovid_act) << 6) & 0x3; - r[15] |= ((u32)(pr->ovid_data) >> 4) & 0xff; - r[16] |= ((u32)(pr->ovid_data) & 0xf) << 28; - r[16] |= ((u32)(pr->nopri_data) & 0x7) << 20; - r[16] |= ((u32)(pr->mpls_act) & 0x7) << 20; - r[16] |= ((u32)(pr->mpls_lib_idx) & 0x7) << 20; - r[16] |= pr->bypass_all ? BIT(9) : 0; - r[16] |= pr->bypass_igr_stp ? BIT(8) : 0; - r[16] |= pr->bypass_ibc_sc ? BIT(7) : 0; -} - -static void rtl839x_read_pie_action(u32 r[], struct pie_rule *pr) -{ - if (r[13] & BIT(3)) { /* ACT_MASK_FWD set, is it a drop? */ - if ((r[14] & 0x7) == 1) { - pr->drop = true; - } else { - pr->fwd_sel = true; - pr->fwd_act = r[14] & 0x7; - } - } - - pr->bypass_sel = r[13] & BIT(11); - pr->mpls_sel = r[13] & BIT(10); - pr->nopri_sel = r[13] & BIT(9); - pr->ovid_sel = r[13] & BIT(8); - pr->ivid_sel = r[13] & BIT(7); - pr->meter_sel = r[13] & BIT(6); - pr->mir_sel = r[13] & BIT(5); - pr->log_sel = r[13] & BIT(4); - - /* TODO: Read in data fields */ - - pr->bypass_all = r[16] & BIT(9); - pr->bypass_igr_stp = r[16] & BIT(8); - pr->bypass_ibc_sc = r[16] & BIT(7); -} - -static void rtl839x_pie_rule_dump_raw(u32 r[]) -{ - pr_debug("Raw IACL table entry:\n"); - pr_debug("Match : %08x %08x %08x %08x %08x %08x\n", r[0], r[1], r[2], r[3], r[4], r[5]); - pr_debug("Fixed : %06x\n", r[6] >> 8); - pr_debug("Match M: %08x %08x %08x %08x %08x %08x\n", - (r[6] << 24) | (r[7] >> 8), (r[7] << 24) | (r[8] >> 8), (r[8] << 24) | (r[9] >> 8), - (r[9] << 24) | (r[10] >> 8), (r[10] << 24) | (r[11] >> 8), - (r[11] << 24) | (r[12] >> 8)); - pr_debug("R[13]: %08x\n", r[13]); - pr_debug("Fixed M: %06x\n", ((r[12] << 16) | (r[13] >> 16)) & 0xffffff); - pr_debug("Valid / not / and1 / and2 : %1x\n", (r[13] >> 12) & 0xf); - pr_debug("r 13-16: %08x %08x %08x %08x\n", r[13], r[14], r[15], r[16]); -} - -void rtl839x_pie_rule_dump(struct pie_rule *pr) -{ - pr_debug("Drop: %d, fwd: %d, ovid: %d, ivid: %d, flt: %d, log: %d, rmk: %d, meter: %d tagst: %d, mir: %d, nopri: %d, cpupri: %d, otpid: %d, itpid: %d, shape: %d\n", - pr->drop, pr->fwd_sel, pr->ovid_sel, pr->ivid_sel, pr->flt_sel, pr->log_sel, pr->rmk_sel, pr->log_sel, pr->tagst_sel, pr->mir_sel, pr->nopri_sel, - pr->cpupri_sel, pr->otpid_sel, pr->itpid_sel, pr->shaper_sel); - if (pr->fwd_sel) - pr_debug("FWD: %08x\n", pr->fwd_data); - pr_debug("TID: %x, %x\n", pr->tid, pr->tid_m); -} - -static int rtl839x_pie_rule_read(struct rtl838x_switch_priv *priv, int idx, struct pie_rule *pr) -{ - int tbl = otto_table_acquire(RTL8390_TBL_IACL); - u32 r[17]; - int block = idx / PIE_BLOCK_SIZE; - u32 t_select = sw_r32(RTL839X_ACL_BLK_TMPLTE_CTRL(block)); - - memset(pr, 0, sizeof(*pr)); - __otto_table_read(tbl, idx, &r); - - otto_table_release(tbl); - - rtl839x_read_pie_fixed_fields(r, pr); - if (!pr->valid) - return 0; - - pr_debug("%s: template_selectors %08x, tid: %d\n", __func__, t_select, pr->tid); - rtl839x_pie_rule_dump_raw(r); - - rtl839x_read_pie_templated(r, pr, rtl839x_fixed_templates[(t_select >> (pr->tid * 3)) & 0x7]); - - rtl839x_read_pie_action(r, pr); - - return 0; -} - -static int rtl839x_pie_rule_write(struct rtl838x_switch_priv *priv, int idx, struct pie_rule *pr) -{ - int tbl = otto_table_acquire(RTL8390_TBL_IACL); - u32 r[17]; - int block = idx / PIE_BLOCK_SIZE; - u32 t_select = sw_r32(RTL839X_ACL_BLK_TMPLTE_CTRL(block)); - - pr_debug("%s: %d, t_select: %08x\n", __func__, idx, t_select); - - for (int i = 0; i < 17; i++) - r[i] = 0; - - if (!pr->valid) { - __otto_table_write(tbl, idx, &r); - otto_table_release(tbl); - return 0; - } - rtl839x_write_pie_fixed_fields(r, pr); - - pr_debug("%s: template %d\n", __func__, (t_select >> (pr->tid * 3)) & 0x7); - rtl839x_write_pie_templated(r, pr, rtl839x_fixed_templates[(t_select >> (pr->tid * 3)) & 0x7]); - - rtl839x_write_pie_action(r, pr); - -/* rtl839x_pie_rule_dump_raw(r); */ - - __otto_table_write(tbl, idx, &r); - otto_table_release(tbl); - - return 0; -} - -static bool rtl839x_pie_templ_has(int t, enum rtl839x_template_field_id field_type) -{ - for (int i = 0; i < N_FIXED_FIELDS; i++) { - enum rtl839x_template_field_id ft = rtl839x_fixed_templates[t][i]; - - if (field_type == ft) - return true; - } - - return false; -} - -static int rtl839x_pie_verify_template(struct rtl838x_switch_priv *priv, - struct pie_rule *pr, int t, int block) -{ - int i; - - if (!pr->is_ipv6 && pr->sip_m && !rtl839x_pie_templ_has(t, RTL839X_TEMPLATE_FIELD_SIP0)) - return -1; - - if (!pr->is_ipv6 && pr->dip_m && !rtl839x_pie_templ_has(t, RTL839X_TEMPLATE_FIELD_DIP0)) - return -1; - - if (pr->is_ipv6) { - if ((pr->sip6_m.s6_addr32[0] || - pr->sip6_m.s6_addr32[1] || - pr->sip6_m.s6_addr32[2] || - pr->sip6_m.s6_addr32[3]) && - !rtl839x_pie_templ_has(t, RTL839X_TEMPLATE_FIELD_SIP2)) - return -1; - if ((pr->dip6_m.s6_addr32[0] || - pr->dip6_m.s6_addr32[1] || - pr->dip6_m.s6_addr32[2] || - pr->dip6_m.s6_addr32[3]) && - !rtl839x_pie_templ_has(t, RTL839X_TEMPLATE_FIELD_DIP2)) - return -1; - } - - if (ether_addr_to_u64(pr->smac_m) && !rtl839x_pie_templ_has(t, RTL839X_TEMPLATE_FIELD_SMAC0)) - return -1; - - if (ether_addr_to_u64(pr->dmac_m) && !rtl839x_pie_templ_has(t, RTL839X_TEMPLATE_FIELD_DMAC0)) - return -1; - - if (pr->itag_m && !rtl839x_pie_templ_has(t, RTL839X_TEMPLATE_FIELD_ITAG)) - return -1; - - if (pr->sport_m && !rtl839x_pie_templ_has(t, RTL839X_TEMPLATE_FIELD_L4_SPORT)) - return -1; - - if (pr->dport_m && !rtl839x_pie_templ_has(t, RTL839X_TEMPLATE_FIELD_L4_DPORT)) - return -1; - - /* TODO: Check more */ - - i = find_first_zero_bit(&priv->pie_use_bm[block * 4], PIE_BLOCK_SIZE); - - if (i >= PIE_BLOCK_SIZE) - return -1; - - return i + PIE_BLOCK_SIZE * block; -} - -static int rtl839x_pie_rule_add(struct rtl838x_switch_priv *priv, struct pie_rule *pr) -{ - int idx, block, j, t; - int min_block = 0; - int max_block = priv->r->n_pie_blocks / 2; - - if (pr->is_egress) { - min_block = max_block; - max_block = priv->r->n_pie_blocks; - } - - mutex_lock(&priv->pie_mutex); - - for (block = min_block; block < max_block; block++) { - for (j = 0; j < 2; j++) { - t = (sw_r32(RTL839X_ACL_BLK_TMPLTE_CTRL(block)) >> (j * 3)) & 0x7; - idx = rtl839x_pie_verify_template(priv, pr, t, block); - if (idx >= 0) - break; - } - if (j < 2) - break; - } - - if (block >= max_block) { - mutex_unlock(&priv->pie_mutex); - return -EOPNOTSUPP; - } - - set_bit(idx, priv->pie_use_bm); - - pr->valid = true; - pr->tid = j; /* Mapped to template number */ - pr->tid_m = 0x3; - pr->id = idx; - - rtl839x_pie_lookup_enable(priv, idx); - rtl839x_pie_rule_write(priv, idx, pr); - - mutex_unlock(&priv->pie_mutex); - - return 0; -} - -static void rtl839x_pie_rule_rm(struct rtl838x_switch_priv *priv, struct pie_rule *pr) -{ - int idx = pr->id; - - rtl839x_pie_rule_del(priv, idx, idx); - clear_bit(idx, priv->pie_use_bm); -} - -static void rtl839x_pie_init(struct rtl838x_switch_priv *priv) -{ - u32 template_selectors; - - mutex_init(&priv->pie_mutex); - - /* Power on all PIE blocks */ - for (int i = 0; i < priv->r->n_pie_blocks; i++) - sw_w32_mask(0, BIT(i), RTL839X_PS_ACL_PWR_CTRL); - - /* Set ingress and egress ACL blocks to 50/50: first Egress block is 9 */ - sw_w32_mask(0x1f, 9, RTL839X_ACL_CTRL); /* Writes 9 to cutline field */ - - /* Include IPG in metering */ - sw_w32(1, RTL839X_METER_GLB_CTRL); - - /* Delete all present rules */ - rtl839x_pie_rule_del(priv, 0, priv->r->n_pie_blocks * PIE_BLOCK_SIZE - 1); - - /* Enable predefined templates 0, 1 for blocks 0-2 */ - template_selectors = 0 | (1 << 3); - for (int i = 0; i < 3; i++) - sw_w32(template_selectors, RTL839X_ACL_BLK_TMPLTE_CTRL(i)); - - /* Enable predefined templates 2, 3 for blocks 3-5 */ - template_selectors = 2 | (3 << 3); - for (int i = 3; i < 6; i++) - sw_w32(template_selectors, RTL839X_ACL_BLK_TMPLTE_CTRL(i)); - - /* Enable predefined templates 1, 4 for blocks 6-8 */ - template_selectors = 2 | (3 << 3); - for (int i = 6; i < 9; i++) - sw_w32(template_selectors, RTL839X_ACL_BLK_TMPLTE_CTRL(i)); - - /* Enable predefined templates 0, 1 for blocks 9-11 */ - template_selectors = 0 | (1 << 3); - for (int i = 9; i < 12; i++) - sw_w32(template_selectors, RTL839X_ACL_BLK_TMPLTE_CTRL(i)); - - /* Enable predefined templates 2, 3 for blocks 12-14 */ - template_selectors = 2 | (3 << 3); - for (int i = 12; i < 15; i++) - sw_w32(template_selectors, RTL839X_ACL_BLK_TMPLTE_CTRL(i)); - - /* Enable predefined templates 1, 4 for blocks 15-17 */ - template_selectors = 2 | (3 << 3); - for (int i = 15; i < 18; i++) - sw_w32(template_selectors, RTL839X_ACL_BLK_TMPLTE_CTRL(i)); -} - static u32 rtl839x_packet_cntr_read(struct rtl838x_switch_priv *priv, int counter) { u32 buf[2]; diff --git a/target/linux/realtek/files-6.18/drivers/net/dsa/rtl83xx/rtl930x.c b/target/linux/realtek/files-6.18/drivers/net/dsa/rtl83xx/rtl930x.c index 5512a1bcd9a..cdcd706f89b 100644 --- a/target/linux/realtek/files-6.18/drivers/net/dsa/rtl83xx/rtl930x.c +++ b/target/linux/realtek/files-6.18/drivers/net/dsa/rtl83xx/rtl930x.c @@ -5,6 +5,7 @@ #include #include "l3.h" +#include "pie.h" #include "rtl-otto.h" #include "tc.h" #include "vlan.h" @@ -25,97 +26,6 @@ /* get shift for given led in any set */ #define RTL930X_LED_SET_LEDX_SHIFT(x) (16 * (x % 2)) -/* Definition of the RTL930X-specific template field IDs as used in the PIE */ -enum rtl930x_template_field_id { - RTL930X_TEMPLATE_FIELD_SPM0 = 0, /* Source portmask ports 0-15 */ - RTL930X_TEMPLATE_FIELD_SPM1 = 1, /* Source portmask ports 16-31 */ - RTL930X_TEMPLATE_FIELD_DMAC0 = 2, /* Destination MAC [15:0] */ - RTL930X_TEMPLATE_FIELD_DMAC1 = 3, /* Destination MAC [31:16] */ - RTL930X_TEMPLATE_FIELD_DMAC2 = 4, /* Destination MAC [47:32] */ - RTL930X_TEMPLATE_FIELD_SMAC0 = 5, /* Source MAC [15:0] */ - RTL930X_TEMPLATE_FIELD_SMAC1 = 6, /* Source MAC [31:16] */ - RTL930X_TEMPLATE_FIELD_SMAC2 = 7, /* Source MAC [47:32] */ - RTL930X_TEMPLATE_FIELD_ETHERTYPE = 8, /* Ethernet frame type field */ - RTL930X_TEMPLATE_FIELD_OTAG = 9, - RTL930X_TEMPLATE_FIELD_ITAG = 10, - RTL930X_TEMPLATE_FIELD_SIP0 = 11, - RTL930X_TEMPLATE_FIELD_SIP1 = 12, - RTL930X_TEMPLATE_FIELD_DIP0 = 13, - RTL930X_TEMPLATE_FIELD_DIP1 = 14, - RTL930X_TEMPLATE_FIELD_IP_TOS_PROTO = 15, - RTL930X_TEMPLATE_FIELD_L4_SPORT = 16, - RTL930X_TEMPLATE_FIELD_L4_DPORT = 17, - RTL930X_TEMPLATE_FIELD_L34_HEADER = 18, - RTL930X_TEMPLATE_FIELD_TCP_INFO = 19, - RTL930X_TEMPLATE_FIELD_FIELD_SELECTOR_VALID = 20, - RTL930X_TEMPLATE_FIELD_FIELD_SELECTOR_0 = 21, - RTL930X_TEMPLATE_FIELD_FIELD_SELECTOR_1 = 22, - RTL930X_TEMPLATE_FIELD_FIELD_SELECTOR_2 = 23, - RTL930X_TEMPLATE_FIELD_FIELD_SELECTOR_3 = 24, - RTL930X_TEMPLATE_FIELD_FIELD_SELECTOR_4 = 25, - RTL930X_TEMPLATE_FIELD_FIELD_SELECTOR_5 = 26, - RTL930X_TEMPLATE_FIELD_SIP2 = 27, - RTL930X_TEMPLATE_FIELD_SIP3 = 28, - RTL930X_TEMPLATE_FIELD_SIP4 = 29, - RTL930X_TEMPLATE_FIELD_SIP5 = 30, - RTL930X_TEMPLATE_FIELD_SIP6 = 31, - RTL930X_TEMPLATE_FIELD_SIP7 = 32, - RTL930X_TEMPLATE_FIELD_DIP2 = 33, - RTL930X_TEMPLATE_FIELD_DIP3 = 34, - RTL930X_TEMPLATE_FIELD_DIP4 = 35, - RTL930X_TEMPLATE_FIELD_DIP5 = 36, - RTL930X_TEMPLATE_FIELD_DIP6 = 37, - RTL930X_TEMPLATE_FIELD_DIP7 = 38, - RTL930X_TEMPLATE_FIELD_PKT_INFO = 39, - RTL930X_TEMPLATE_FIELD_FLOW_LABEL = 40, - RTL930X_TEMPLATE_FIELD_DSAP_SSAP = 41, - RTL930X_TEMPLATE_FIELD_SNAP_OUI = 42, - RTL930X_TEMPLATE_FIELD_FWD_VID = 43, - RTL930X_TEMPLATE_FIELD_RANGE_CHK = 44, - RTL930X_TEMPLATE_FIELD_VLAN_GMSK = 45, /* VLAN Group Mask/IP range check */ - RTL930X_TEMPLATE_FIELD_DLP = 46, - RTL930X_TEMPLATE_FIELD_META_DATA = 47, - RTL930X_TEMPLATE_FIELD_SRC_FWD_VID = 48, - RTL930X_TEMPLATE_FIELD_SLP = 49, -}; - -/* The meaning of RTL930X_TEMPLATE_FIELD_VLAN depends on phase and the configuration in - * RTL930X_PIE_CTRL. We use always the same definition and map to the inner VLAN tag: - */ -#define RTL930X_TEMPLATE_FIELD_VLAN RTL930X_TEMPLATE_FIELD_ITAG - -/* Number of fixed templates predefined in the RTL9300 SoC */ -#define RTL930X_N_FIXED_TEMPLATES 5 -/* RTL9300 specific predefined templates */ -static enum rtl930x_template_field_id rtl930x_fixed_templates[RTL930X_N_FIXED_TEMPLATES][N_FIXED_FIELDS] = { - { - RTL930X_TEMPLATE_FIELD_DMAC0, RTL930X_TEMPLATE_FIELD_DMAC1, RTL930X_TEMPLATE_FIELD_DMAC2, - RTL930X_TEMPLATE_FIELD_SMAC0, RTL930X_TEMPLATE_FIELD_SMAC1, RTL930X_TEMPLATE_FIELD_SMAC2, - RTL930X_TEMPLATE_FIELD_VLAN, RTL930X_TEMPLATE_FIELD_IP_TOS_PROTO, RTL930X_TEMPLATE_FIELD_DSAP_SSAP, - RTL930X_TEMPLATE_FIELD_ETHERTYPE, RTL930X_TEMPLATE_FIELD_SPM0, RTL930X_TEMPLATE_FIELD_SPM1 - }, { - RTL930X_TEMPLATE_FIELD_SIP0, RTL930X_TEMPLATE_FIELD_SIP1, RTL930X_TEMPLATE_FIELD_DIP0, - RTL930X_TEMPLATE_FIELD_DIP1, RTL930X_TEMPLATE_FIELD_IP_TOS_PROTO, RTL930X_TEMPLATE_FIELD_TCP_INFO, - RTL930X_TEMPLATE_FIELD_L4_SPORT, RTL930X_TEMPLATE_FIELD_L4_DPORT, RTL930X_TEMPLATE_FIELD_VLAN, - RTL930X_TEMPLATE_FIELD_RANGE_CHK, RTL930X_TEMPLATE_FIELD_SPM0, RTL930X_TEMPLATE_FIELD_SPM1 - }, { - RTL930X_TEMPLATE_FIELD_DMAC0, RTL930X_TEMPLATE_FIELD_DMAC1, RTL930X_TEMPLATE_FIELD_DMAC2, - RTL930X_TEMPLATE_FIELD_VLAN, RTL930X_TEMPLATE_FIELD_ETHERTYPE, RTL930X_TEMPLATE_FIELD_IP_TOS_PROTO, - RTL930X_TEMPLATE_FIELD_SIP0, RTL930X_TEMPLATE_FIELD_SIP1, RTL930X_TEMPLATE_FIELD_DIP0, - RTL930X_TEMPLATE_FIELD_DIP1, RTL930X_TEMPLATE_FIELD_L4_SPORT, RTL930X_TEMPLATE_FIELD_L4_DPORT - }, { - RTL930X_TEMPLATE_FIELD_DIP0, RTL930X_TEMPLATE_FIELD_DIP1, RTL930X_TEMPLATE_FIELD_DIP2, - RTL930X_TEMPLATE_FIELD_DIP3, RTL930X_TEMPLATE_FIELD_DIP4, RTL930X_TEMPLATE_FIELD_DIP5, - RTL930X_TEMPLATE_FIELD_DIP6, RTL930X_TEMPLATE_FIELD_DIP7, RTL930X_TEMPLATE_FIELD_IP_TOS_PROTO, - RTL930X_TEMPLATE_FIELD_TCP_INFO, RTL930X_TEMPLATE_FIELD_L4_SPORT, RTL930X_TEMPLATE_FIELD_L4_DPORT - }, { - RTL930X_TEMPLATE_FIELD_SIP0, RTL930X_TEMPLATE_FIELD_SIP1, RTL930X_TEMPLATE_FIELD_SIP2, - RTL930X_TEMPLATE_FIELD_SIP3, RTL930X_TEMPLATE_FIELD_SIP4, RTL930X_TEMPLATE_FIELD_SIP5, - RTL930X_TEMPLATE_FIELD_SIP6, RTL930X_TEMPLATE_FIELD_SIP7, RTL930X_TEMPLATE_FIELD_VLAN, - RTL930X_TEMPLATE_FIELD_RANGE_CHK, RTL930X_TEMPLATE_FIELD_SPM1, RTL930X_TEMPLATE_FIELD_SPM1 - }, -}; - const struct rtldsa_mib_list_item rtldsa_930x_mib_list[] = { MIB_LIST_ITEM("ifOutDiscards", MIB_ITEM(MIB_REG_STD, 0xbc, 1)), MIB_LIST_ITEM("dot1dTpPortInDiscards", MIB_ITEM(MIB_REG_STD, 0xb8, 1)), @@ -1097,541 +1007,6 @@ static void rtl930x_init_eee(struct rtl838x_switch_priv *priv, bool enable) #endif /* CONFIG_NET_DSA_RTL83XX_RTL930X_L3_OFFLOAD */ -static void rtl930x_pie_lookup_enable(struct rtl838x_switch_priv *priv, int index) -{ - int block = index / PIE_BLOCK_SIZE; - - sw_w32_mask(0, BIT(block), RTL930X_PIE_BLK_LOOKUP_CTRL); -} - -/* Reads the intermediate representation of the templated match-fields of the - * PIE rule in the pie_rule structure and fills in the raw data fields in the - * raw register space r[]. - * The register space configuration size is identical for the RTL8380/90 and RTL9300, - * however the RTL9310 has 2 more registers / fields and the physical field-ids are different - * on all SoCs - * On the RTL9300 the mask fields are not word-aligend! - */ -static void rtl930x_write_pie_templated(u32 r[], struct pie_rule *pr, enum rtl930x_template_field_id t[]) -{ - for (int i = 0; i < N_FIXED_FIELDS; i++) { - enum rtl930x_template_field_id field_type = t[i]; - u16 data = 0, data_m = 0; - - switch (field_type) { - case RTL930X_TEMPLATE_FIELD_SPM0: - data = pr->spm; - data_m = pr->spm_m; - break; - case RTL930X_TEMPLATE_FIELD_SPM1: - data = pr->spm >> 16; - data_m = pr->spm_m >> 16; - break; - case RTL930X_TEMPLATE_FIELD_OTAG: - data = pr->otag; - data_m = pr->otag_m; - break; - case RTL930X_TEMPLATE_FIELD_SMAC0: - data = pr->smac[4]; - data = (data << 8) | pr->smac[5]; - data_m = pr->smac_m[4]; - data_m = (data_m << 8) | pr->smac_m[5]; - break; - case RTL930X_TEMPLATE_FIELD_SMAC1: - data = pr->smac[2]; - data = (data << 8) | pr->smac[3]; - data_m = pr->smac_m[2]; - data_m = (data_m << 8) | pr->smac_m[3]; - break; - case RTL930X_TEMPLATE_FIELD_SMAC2: - data = pr->smac[0]; - data = (data << 8) | pr->smac[1]; - data_m = pr->smac_m[0]; - data_m = (data_m << 8) | pr->smac_m[1]; - break; - case RTL930X_TEMPLATE_FIELD_DMAC0: - data = pr->dmac[4]; - data = (data << 8) | pr->dmac[5]; - data_m = pr->dmac_m[4]; - data_m = (data_m << 8) | pr->dmac_m[5]; - break; - case RTL930X_TEMPLATE_FIELD_DMAC1: - data = pr->dmac[2]; - data = (data << 8) | pr->dmac[3]; - data_m = pr->dmac_m[2]; - data_m = (data_m << 8) | pr->dmac_m[3]; - break; - case RTL930X_TEMPLATE_FIELD_DMAC2: - data = pr->dmac[0]; - data = (data << 8) | pr->dmac[1]; - data_m = pr->dmac_m[0]; - data_m = (data_m << 8) | pr->dmac_m[1]; - break; - case RTL930X_TEMPLATE_FIELD_ETHERTYPE: - data = pr->ethertype; - data_m = pr->ethertype_m; - break; - case RTL930X_TEMPLATE_FIELD_ITAG: - data = pr->itag; - data_m = pr->itag_m; - break; - case RTL930X_TEMPLATE_FIELD_SIP0: - if (pr->is_ipv6) { - data = pr->sip6.s6_addr16[7]; - data_m = pr->sip6_m.s6_addr16[7]; - } else { - data = pr->sip; - data_m = pr->sip_m; - } - break; - case RTL930X_TEMPLATE_FIELD_SIP1: - if (pr->is_ipv6) { - data = pr->sip6.s6_addr16[6]; - data_m = pr->sip6_m.s6_addr16[6]; - } else { - data = pr->sip >> 16; - data_m = pr->sip_m >> 16; - } - break; - case RTL930X_TEMPLATE_FIELD_SIP2: - case RTL930X_TEMPLATE_FIELD_SIP3: - case RTL930X_TEMPLATE_FIELD_SIP4: - case RTL930X_TEMPLATE_FIELD_SIP5: - case RTL930X_TEMPLATE_FIELD_SIP6: - case RTL930X_TEMPLATE_FIELD_SIP7: - data = pr->sip6.s6_addr16[5 - (field_type - RTL930X_TEMPLATE_FIELD_SIP2)]; - data_m = pr->sip6_m.s6_addr16[5 - (field_type - RTL930X_TEMPLATE_FIELD_SIP2)]; - break; - case RTL930X_TEMPLATE_FIELD_DIP0: - if (pr->is_ipv6) { - data = pr->dip6.s6_addr16[7]; - data_m = pr->dip6_m.s6_addr16[7]; - } else { - data = pr->dip; - data_m = pr->dip_m; - } - break; - case RTL930X_TEMPLATE_FIELD_DIP1: - if (pr->is_ipv6) { - data = pr->dip6.s6_addr16[6]; - data_m = pr->dip6_m.s6_addr16[6]; - } else { - data = pr->dip >> 16; - data_m = pr->dip_m >> 16; - } - break; - case RTL930X_TEMPLATE_FIELD_DIP2: - case RTL930X_TEMPLATE_FIELD_DIP3: - case RTL930X_TEMPLATE_FIELD_DIP4: - case RTL930X_TEMPLATE_FIELD_DIP5: - case RTL930X_TEMPLATE_FIELD_DIP6: - case RTL930X_TEMPLATE_FIELD_DIP7: - data = pr->dip6.s6_addr16[5 - (field_type - RTL930X_TEMPLATE_FIELD_DIP2)]; - data_m = pr->dip6_m.s6_addr16[5 - (field_type - RTL930X_TEMPLATE_FIELD_DIP2)]; - break; - case RTL930X_TEMPLATE_FIELD_IP_TOS_PROTO: - data = pr->tos_proto; - data_m = pr->tos_proto_m; - break; - case RTL930X_TEMPLATE_FIELD_L4_SPORT: - data = pr->sport; - data_m = pr->sport_m; - break; - case RTL930X_TEMPLATE_FIELD_L4_DPORT: - data = pr->dport; - data_m = pr->dport_m; - break; - case RTL930X_TEMPLATE_FIELD_DSAP_SSAP: - data = pr->dsap_ssap; - data_m = pr->dsap_ssap_m; - break; - case RTL930X_TEMPLATE_FIELD_TCP_INFO: - data = pr->tcp_info; - data_m = pr->tcp_info_m; - break; - case RTL930X_TEMPLATE_FIELD_RANGE_CHK: - pr_debug("RTL930X_TEMPLATE_FIELD_RANGE_CHK: not configured\n"); - break; - default: - pr_debug("%s: unknown field %d\n", __func__, field_type); - } - - /* On the RTL9300, the mask fields are not word aligned! */ - if (!(i % 2)) { - r[5 - i / 2] = data; - r[12 - i / 2] |= ((u32)data_m << 8); - } else { - r[5 - i / 2] |= ((u32)data) << 16; - r[12 - i / 2] |= ((u32)data_m) << 24; - r[11 - i / 2] |= ((u32)data_m) >> 8; - } - } -} - -// Currently not used -// static void rtl930x_read_pie_fixed_fields(u32 r[], struct pie_rule *pr) -// { -// pr->stacking_port = r[6] & BIT(31); -// pr->spn = (r[6] >> 24) & 0x7f; -// pr->mgnt_vlan = r[6] & BIT(23); -// if (pr->phase == PHASE_IACL) -// pr->dmac_hit_sw = r[6] & BIT(22); -// else -// pr->content_too_deep = r[6] & BIT(22); -// pr->not_first_frag = r[6] & BIT(21); -// pr->frame_type_l4 = (r[6] >> 18) & 7; -// pr->frame_type = (r[6] >> 16) & 3; -// pr->otag_fmt = (r[6] >> 15) & 1; -// pr->itag_fmt = (r[6] >> 14) & 1; -// pr->otag_exist = (r[6] >> 13) & 1; -// pr->itag_exist = (r[6] >> 12) & 1; -// pr->frame_type_l2 = (r[6] >> 10) & 3; -// pr->igr_normal_port = (r[6] >> 9) & 1; -// pr->tid = (r[6] >> 8) & 1; - -// pr->stacking_port_m = r[12] & BIT(7); -// pr->spn_m = r[12] & 0x7f; -// pr->mgnt_vlan_m = r[13] & BIT(31); -// if (pr->phase == PHASE_IACL) -// pr->dmac_hit_sw_m = r[13] & BIT(30); -// else -// pr->content_too_deep_m = r[13] & BIT(30); -// pr->not_first_frag_m = r[13] & BIT(29); -// pr->frame_type_l4_m = (r[13] >> 26) & 7; -// pr->frame_type_m = (r[13] >> 24) & 3; -// pr->otag_fmt_m = r[13] & BIT(23); -// pr->itag_fmt_m = r[13] & BIT(22); -// pr->otag_exist_m = r[13] & BIT(21); -// pr->itag_exist_m = r[13] & BIT (20); -// pr->frame_type_l2_m = (r[13] >> 18) & 3; -// pr->igr_normal_port_m = r[13] & BIT(17); -// pr->tid_m = (r[13] >> 16) & 1; - -// pr->valid = r[13] & BIT(15); -// pr->cond_not = r[13] & BIT(14); -// pr->cond_and1 = r[13] & BIT(13); -// pr->cond_and2 = r[13] & BIT(12); -// } - -static void rtl930x_write_pie_fixed_fields(u32 r[], struct pie_rule *pr) -{ - r[6] = pr->stacking_port ? BIT(31) : 0; - r[6] |= ((u32)(pr->spn & 0x7f)) << 24; - r[6] |= pr->mgnt_vlan ? BIT(23) : 0; - if (pr->phase == PHASE_IACL) - r[6] |= pr->dmac_hit_sw ? BIT(22) : 0; - else - r[6] |= pr->content_too_deep ? BIT(22) : 0; - r[6] |= pr->not_first_frag ? BIT(21) : 0; - r[6] |= ((u32)(pr->frame_type_l4 & 0x7)) << 18; - r[6] |= ((u32)(pr->frame_type & 0x3)) << 16; - r[6] |= pr->otag_fmt ? BIT(15) : 0; - r[6] |= pr->itag_fmt ? BIT(14) : 0; - r[6] |= pr->otag_exist ? BIT(13) : 0; - r[6] |= pr->itag_exist ? BIT(12) : 0; - r[6] |= ((u32)(pr->frame_type_l2 & 0x3)) << 10; - r[6] |= pr->igr_normal_port ? BIT(9) : 0; - r[6] |= ((u32)(pr->tid & 0x1)) << 8; - - r[12] |= pr->stacking_port_m ? BIT(7) : 0; - r[12] |= (u32)(pr->spn_m & 0x7f); - r[13] |= pr->mgnt_vlan_m ? BIT(31) : 0; - if (pr->phase == PHASE_IACL) - r[13] |= pr->dmac_hit_sw_m ? BIT(30) : 0; - else - r[13] |= pr->content_too_deep_m ? BIT(30) : 0; - r[13] |= pr->not_first_frag_m ? BIT(29) : 0; - r[13] |= ((u32)(pr->frame_type_l4_m & 0x7)) << 26; - r[13] |= ((u32)(pr->frame_type_m & 0x3)) << 24; - r[13] |= pr->otag_fmt_m ? BIT(23) : 0; - r[13] |= pr->itag_fmt_m ? BIT(22) : 0; - r[13] |= pr->otag_exist_m ? BIT(21) : 0; - r[13] |= pr->itag_exist_m ? BIT(20) : 0; - r[13] |= ((u32)(pr->frame_type_l2_m & 0x3)) << 18; - r[13] |= pr->igr_normal_port_m ? BIT(17) : 0; - r[13] |= ((u32)(pr->tid_m & 0x1)) << 16; - - r[13] |= pr->valid ? BIT(15) : 0; - r[13] |= pr->cond_not ? BIT(14) : 0; - r[13] |= pr->cond_and1 ? BIT(13) : 0; - r[13] |= pr->cond_and2 ? BIT(12) : 0; -} - -static void rtl930x_write_pie_action(u32 r[], struct pie_rule *pr) -{ - /* Either drop or forward */ - if (pr->drop) { - r[14] |= BIT(24) | BIT(25) | BIT(26); /* Do Green, Yellow and Red drops */ - /* Actually DROP, not PERMIT in Green / Yellow / Red */ - r[14] |= BIT(23) | BIT(22) | BIT(20); - } else { - r[14] |= pr->fwd_sel ? BIT(27) : 0; - r[14] |= pr->fwd_act << 18; - r[14] |= BIT(14); /* We overwrite any drop */ - } - if (pr->phase == PHASE_VACL) - r[14] |= pr->fwd_sa_lrn ? BIT(15) : 0; - r[13] |= pr->bypass_sel ? BIT(5) : 0; - r[13] |= pr->nopri_sel ? BIT(4) : 0; - r[13] |= pr->tagst_sel ? BIT(3) : 0; - r[13] |= pr->ovid_sel ? BIT(1) : 0; - r[14] |= pr->ivid_sel ? BIT(31) : 0; - r[14] |= pr->meter_sel ? BIT(30) : 0; - r[14] |= pr->mir_sel ? BIT(29) : 0; - r[14] |= pr->log_sel ? BIT(28) : 0; - - r[14] |= ((u32)(pr->fwd_data & 0x3fff)) << 3; - r[15] |= pr->log_octets ? BIT(31) : 0; - r[15] |= (u32)(pr->meter_data) << 23; - - r[15] |= ((u32)(pr->ivid_act) & 0x3) << 21; - r[15] |= ((u32)(pr->ivid_data) & 0xfff) << 9; - r[16] |= ((u32)(pr->ovid_act) & 0x3) << 30; - r[16] |= ((u32)(pr->ovid_data) & 0xfff) << 16; - r[16] |= (pr->mir_data & 0x3) << 6; - r[17] |= ((u32)(pr->tagst_data) & 0xf) << 28; - r[17] |= ((u32)(pr->nopri_data) & 0x7) << 25; - r[17] |= pr->bypass_ibc_sc ? BIT(16) : 0; -} - -void rtl930x_pie_rule_dump_raw(u32 r[]) -{ - pr_debug("Raw IACL table entry:\n"); - pr_debug("r 0 - 7: %08x %08x %08x %08x %08x %08x %08x %08x\n", - r[0], r[1], r[2], r[3], r[4], r[5], r[6], r[7]); - pr_debug("r 8 - 15: %08x %08x %08x %08x %08x %08x %08x %08x\n", - r[8], r[9], r[10], r[11], r[12], r[13], r[14], r[15]); - pr_debug("r 16 - 18: %08x %08x %08x\n", r[16], r[17], r[18]); - pr_debug("Match : %08x %08x %08x %08x %08x %08x\n", r[0], r[1], r[2], r[3], r[4], r[5]); - pr_debug("Fixed : %06x\n", r[6] >> 8); - pr_debug("Match M: %08x %08x %08x %08x %08x %08x\n", - (r[6] << 24) | (r[7] >> 8), (r[7] << 24) | (r[8] >> 8), (r[8] << 24) | (r[9] >> 8), - (r[9] << 24) | (r[10] >> 8), (r[10] << 24) | (r[11] >> 8), - (r[11] << 24) | (r[12] >> 8)); - pr_debug("R[13]: %08x\n", r[13]); - pr_debug("Fixed M: %06x\n", ((r[12] << 16) | (r[13] >> 16)) & 0xffffff); - pr_debug("Valid / not / and1 / and2 : %1x\n", (r[13] >> 12) & 0xf); - pr_debug("r 13-16: %08x %08x %08x %08x\n", r[13], r[14], r[15], r[16]); -} - -static int rtl930x_pie_rule_write(struct rtl838x_switch_priv *priv, int idx, struct pie_rule *pr) -{ - int tbl = otto_table_acquire(RTL9300_TBL_IACL); - u32 r[19]; - int block = idx / PIE_BLOCK_SIZE; - u32 t_select = sw_r32(RTL930X_PIE_BLK_TMPLTE_CTRL(block)); - - pr_debug("%s: %d, t_select: %08x\n", __func__, idx, t_select); - - for (int i = 0; i < 19; i++) - r[i] = 0; - - if (!pr->valid) { - __otto_table_write(tbl, idx, &r); - otto_table_release(tbl); - return 0; - } - rtl930x_write_pie_fixed_fields(r, pr); - - pr_debug("%s: template %d\n", __func__, (t_select >> (pr->tid * 4)) & 0xf); - rtl930x_write_pie_templated(r, pr, rtl930x_fixed_templates[(t_select >> (pr->tid * 4)) & 0xf]); - - rtl930x_write_pie_action(r, pr); - -/* rtl930x_pie_rule_dump_raw(r); */ - - __otto_table_write(tbl, idx, &r); - otto_table_release(tbl); - - return 0; -} - -static bool rtl930x_pie_templ_has(int t, enum rtl930x_template_field_id field_type) -{ - for (int i = 0; i < N_FIXED_FIELDS; i++) { - enum rtl930x_template_field_id ft = rtl930x_fixed_templates[t][i]; - - if (field_type == ft) - return true; - } - - return false; -} - -/* Verify that the rule pr is compatible with a given template t in block - * Note that this function is SoC specific since the values of e.g. RTL930X_TEMPLATE_FIELD_SIP0 - * depend on the SoC - */ -static int rtl930x_pie_verify_template(struct rtl838x_switch_priv *priv, - struct pie_rule *pr, int t, int block) -{ - int i; - - if (!pr->is_ipv6 && pr->sip_m && !rtl930x_pie_templ_has(t, RTL930X_TEMPLATE_FIELD_SIP0)) - return -1; - - if (!pr->is_ipv6 && pr->dip_m && !rtl930x_pie_templ_has(t, RTL930X_TEMPLATE_FIELD_DIP0)) - return -1; - - if (pr->is_ipv6) { - if ((pr->sip6_m.s6_addr32[0] || - pr->sip6_m.s6_addr32[1] || - pr->sip6_m.s6_addr32[2] || - pr->sip6_m.s6_addr32[3]) && - !rtl930x_pie_templ_has(t, RTL930X_TEMPLATE_FIELD_SIP2)) - return -1; - if ((pr->dip6_m.s6_addr32[0] || - pr->dip6_m.s6_addr32[1] || - pr->dip6_m.s6_addr32[2] || - pr->dip6_m.s6_addr32[3]) && - !rtl930x_pie_templ_has(t, RTL930X_TEMPLATE_FIELD_DIP2)) - return -1; - } - - if (ether_addr_to_u64(pr->smac_m) && !rtl930x_pie_templ_has(t, RTL930X_TEMPLATE_FIELD_SMAC0)) - return -1; - - if (ether_addr_to_u64(pr->dmac_m) && !rtl930x_pie_templ_has(t, RTL930X_TEMPLATE_FIELD_DMAC0)) - return -1; - - if (pr->ethertype_m && !rtl930x_pie_templ_has(t, RTL930X_TEMPLATE_FIELD_ETHERTYPE)) - return -1; - - if (pr->itag_m && !rtl930x_pie_templ_has(t, RTL930X_TEMPLATE_FIELD_VLAN)) - return -1; - - if (pr->sport_m && !rtl930x_pie_templ_has(t, RTL930X_TEMPLATE_FIELD_L4_SPORT)) - return -1; - - if (pr->dport_m && !rtl930x_pie_templ_has(t, RTL930X_TEMPLATE_FIELD_L4_DPORT)) - return -1; - - /* TODO: Check more */ - - i = find_first_zero_bit(&priv->pie_use_bm[block * 4], PIE_BLOCK_SIZE); - - if (i >= PIE_BLOCK_SIZE) - return -1; - - return i + PIE_BLOCK_SIZE * block; -} - -static int rtl930x_pie_rule_add(struct rtl838x_switch_priv *priv, struct pie_rule *pr) -{ - int idx, block, j, t; - int min_block = 0; - int max_block = priv->r->n_pie_blocks / 2; - - if (pr->is_egress) { - min_block = max_block; - max_block = priv->r->n_pie_blocks; - } - pr_debug("In %s\n", __func__); - - mutex_lock(&priv->pie_mutex); - - for (block = min_block; block < max_block; block++) { - for (j = 0; j < 2; j++) { - t = (sw_r32(RTL930X_PIE_BLK_TMPLTE_CTRL(block)) >> (j * 4)) & 0xf; - pr_debug("Testing block %d, template %d, template id %d\n", block, j, t); - pr_debug("%s: %08x\n", - __func__, sw_r32(RTL930X_PIE_BLK_TMPLTE_CTRL(block))); - idx = rtl930x_pie_verify_template(priv, pr, t, block); - if (idx >= 0) - break; - } - if (j < 2) - break; - } - - if (block >= max_block) { - mutex_unlock(&priv->pie_mutex); - return -EOPNOTSUPP; - } - - pr_debug("Using block: %d, index %d, template-id %d\n", block, idx, j); - set_bit(idx, priv->pie_use_bm); - - pr->valid = true; - pr->tid = j; /* Mapped to template number */ - pr->tid_m = 0x1; - pr->id = idx; - - rtl930x_pie_lookup_enable(priv, idx); - rtl930x_pie_rule_write(priv, idx, pr); - - mutex_unlock(&priv->pie_mutex); - return 0; -} - -/* Delete a range of Packet Inspection Engine rules */ -static int rtl930x_pie_rule_del(struct rtl838x_switch_priv *priv, int index_from, int index_to) -{ - u32 v = (index_from << 1) | (index_to << 12) | BIT(0); - - pr_debug("%s: from %d to %d\n", __func__, index_from, index_to); - mutex_lock(&priv->reg_mutex); - - /* Write from-to and execute bit into control register */ - sw_w32(v, RTL930X_PIE_CLR_CTRL); - - /* Wait until command has completed */ - do { - } while (sw_r32(RTL930X_PIE_CLR_CTRL) & BIT(0)); - - mutex_unlock(&priv->reg_mutex); - return 0; -} - -static void rtl930x_pie_rule_rm(struct rtl838x_switch_priv *priv, struct pie_rule *pr) -{ - int idx = pr->id; - - rtl930x_pie_rule_del(priv, idx, idx); - clear_bit(idx, priv->pie_use_bm); -} - -static void rtl930x_pie_init(struct rtl838x_switch_priv *priv) -{ - u32 template_selectors; - - mutex_init(&priv->pie_mutex); - - pr_debug("%s\n", __func__); - /* Enable ACL lookup on all ports, including CPU_PORT */ - for (int i = 0; i <= priv->r->cpu_port; i++) - sw_w32(1, RTL930X_ACL_PORT_LOOKUP_CTRL(i)); - - /* Include IPG in metering */ - sw_w32_mask(0, 1, RTL930X_METER_GLB_CTRL); - - /* Delete all present rules, block size is 128 on all SoC families */ - rtl930x_pie_rule_del(priv, 0, priv->r->n_pie_blocks * 128 - 1); - - /* Assign blocks 0-7 to VACL phase (bit = 0), blocks 8-15 to IACL (bit = 1) */ - sw_w32(0xff00, RTL930X_PIE_BLK_PHASE_CTRL); - - /* Enable predefined templates 0, 1 for first quarter of all blocks */ - template_selectors = 0 | (1 << 4); - for (int i = 0; i < priv->r->n_pie_blocks / 4; i++) - sw_w32(template_selectors, RTL930X_PIE_BLK_TMPLTE_CTRL(i)); - - /* Enable predefined templates 2, 3 for second quarter of all blocks */ - template_selectors = 2 | (3 << 4); - for (int i = priv->r->n_pie_blocks / 4; i < priv->r->n_pie_blocks / 2; i++) - sw_w32(template_selectors, RTL930X_PIE_BLK_TMPLTE_CTRL(i)); - - /* Enable predefined templates 0, 1 for third half of all blocks */ - template_selectors = 0 | (1 << 4); - for (int i = priv->r->n_pie_blocks / 2; i < priv->r->n_pie_blocks * 3 / 4; i++) - sw_w32(template_selectors, RTL930X_PIE_BLK_TMPLTE_CTRL(i)); - - /* Enable predefined templates 2, 3 for fourth quater of all blocks */ - template_selectors = 2 | (3 << 4); - for (int i = priv->r->n_pie_blocks * 3 / 4; i < priv->r->n_pie_blocks; i++) - sw_w32(template_selectors, RTL930X_PIE_BLK_TMPLTE_CTRL(i)); -} - /* A PIE rule logs its matched packets into the LOG table entry that carries * its own rule ID, in data word 1 - one entry per rule. Counters handed out * by rtldsa_packet_cntr_alloc() for L3 route statistics start above the PIE diff --git a/target/linux/realtek/files-6.18/drivers/net/dsa/rtl83xx/rtl931x.c b/target/linux/realtek/files-6.18/drivers/net/dsa/rtl83xx/rtl931x.c index 00477dad62a..37afcde0c2b 100644 --- a/target/linux/realtek/files-6.18/drivers/net/dsa/rtl83xx/rtl931x.c +++ b/target/linux/realtek/files-6.18/drivers/net/dsa/rtl83xx/rtl931x.c @@ -3,6 +3,7 @@ #include #include +#include "pie.h" #include "rtl-otto.h" #include "tc.h" #include "vlan.h" @@ -13,96 +14,6 @@ #define RTL931X_LED_CLK_SEL_200NS 2 #define RTL931X_LED_CLK_SEL_100NS 3 -/* Definition of the RTL931X-specific template field IDs as used in the PIE */ -enum rtl931x_template_field_id { - RTL931X_TEMPLATE_FIELD_SPM0 = 1, - RTL931X_TEMPLATE_FIELD_SPM1 = 2, - RTL931X_TEMPLATE_FIELD_SPM2 = 3, - RTL931X_TEMPLATE_FIELD_SPM3 = 4, - RTL931X_TEMPLATE_FIELD_DMAC0 = 9, - RTL931X_TEMPLATE_FIELD_DMAC1 = 10, - RTL931X_TEMPLATE_FIELD_DMAC2 = 11, - RTL931X_TEMPLATE_FIELD_SMAC0 = 12, - RTL931X_TEMPLATE_FIELD_SMAC1 = 13, - RTL931X_TEMPLATE_FIELD_SMAC2 = 14, - RTL931X_TEMPLATE_FIELD_ETHERTYPE = 15, - RTL931X_TEMPLATE_FIELD_OTAG = 16, - RTL931X_TEMPLATE_FIELD_ITAG = 17, - RTL931X_TEMPLATE_FIELD_SIP0 = 18, - RTL931X_TEMPLATE_FIELD_SIP1 = 19, - RTL931X_TEMPLATE_FIELD_DIP0 = 20, - RTL931X_TEMPLATE_FIELD_DIP1 = 21, - RTL931X_TEMPLATE_FIELD_IP_TOS_PROTO = 22, - RTL931X_TEMPLATE_FIELD_L4_SPORT = 23, - RTL931X_TEMPLATE_FIELD_L4_DPORT = 24, - RTL931X_TEMPLATE_FIELD_L34_HEADER = 25, - RTL931X_TEMPLATE_FIELD_TCP_INFO = 26, - RTL931X_TEMPLATE_FIELD_SIP2 = 34, - RTL931X_TEMPLATE_FIELD_SIP3 = 35, - RTL931X_TEMPLATE_FIELD_SIP4 = 36, - RTL931X_TEMPLATE_FIELD_SIP5 = 37, - RTL931X_TEMPLATE_FIELD_SIP6 = 38, - RTL931X_TEMPLATE_FIELD_SIP7 = 39, - RTL931X_TEMPLATE_FIELD_DIP2 = 42, - RTL931X_TEMPLATE_FIELD_DIP3 = 43, - RTL931X_TEMPLATE_FIELD_DIP4 = 44, - RTL931X_TEMPLATE_FIELD_DIP5 = 45, - RTL931X_TEMPLATE_FIELD_DIP6 = 46, - RTL931X_TEMPLATE_FIELD_DIP7 = 47, - RTL931X_TEMPLATE_FIELD_FLOW_LABEL = 49, - RTL931X_TEMPLATE_FIELD_DSAP_SSAP = 50, - RTL931X_TEMPLATE_FIELD_FWD_VID = 52, - RTL931X_TEMPLATE_FIELD_RANGE_CHK = 53, - RTL931X_TEMPLATE_FIELD_SLP = 55, - RTL931X_TEMPLATE_FIELD_DLP = 56, - RTL931X_TEMPLATE_FIELD_META_DATA = 57, - RTL931X_TEMPLATE_FIELD_FIRST_MPLS1 = 60, - RTL931X_TEMPLATE_FIELD_FIRST_MPLS2 = 61, - RTL931X_TEMPLATE_FIELD_DPM3 = 8, -}; - -/* The meaning of RTL931X_TEMPLATE_FIELD_VLAN depends on phase and the configuration in - * RTL931X_PIE_CTRL. We use always the same definition and map to the inner VLAN tag: - */ -#define RTL931X_TEMPLATE_FIELD_VLAN RTL931X_TEMPLATE_FIELD_ITAG - -/* Number of fixed templates predefined in the RTL9300 SoC */ -#define RTL931X_N_FIXED_TEMPLATES 5 -/* RTL931x specific predefined templates */ -static enum rtl931x_template_field_id rtl931x_fixed_templates[RTL931X_N_FIXED_TEMPLATES][N_FIXED_FIELDS_RTL931X] = { - { - RTL931X_TEMPLATE_FIELD_DMAC0, RTL931X_TEMPLATE_FIELD_DMAC1, RTL931X_TEMPLATE_FIELD_DMAC2, - RTL931X_TEMPLATE_FIELD_SMAC0, RTL931X_TEMPLATE_FIELD_SMAC1, RTL931X_TEMPLATE_FIELD_SMAC2, - RTL931X_TEMPLATE_FIELD_VLAN, RTL931X_TEMPLATE_FIELD_IP_TOS_PROTO, RTL931X_TEMPLATE_FIELD_DSAP_SSAP, - RTL931X_TEMPLATE_FIELD_ETHERTYPE, RTL931X_TEMPLATE_FIELD_SPM0, RTL931X_TEMPLATE_FIELD_SPM1, - RTL931X_TEMPLATE_FIELD_SPM2, RTL931X_TEMPLATE_FIELD_SPM3 - }, { - RTL931X_TEMPLATE_FIELD_SIP0, RTL931X_TEMPLATE_FIELD_SIP1, RTL931X_TEMPLATE_FIELD_DIP0, - RTL931X_TEMPLATE_FIELD_DIP1, RTL931X_TEMPLATE_FIELD_IP_TOS_PROTO, RTL931X_TEMPLATE_FIELD_TCP_INFO, - RTL931X_TEMPLATE_FIELD_L4_SPORT, RTL931X_TEMPLATE_FIELD_L4_DPORT, RTL931X_TEMPLATE_FIELD_VLAN, - RTL931X_TEMPLATE_FIELD_RANGE_CHK, RTL931X_TEMPLATE_FIELD_SPM0, RTL931X_TEMPLATE_FIELD_SPM1, - RTL931X_TEMPLATE_FIELD_SPM2, RTL931X_TEMPLATE_FIELD_SPM3 - }, { - RTL931X_TEMPLATE_FIELD_DMAC0, RTL931X_TEMPLATE_FIELD_DMAC1, RTL931X_TEMPLATE_FIELD_DMAC2, - RTL931X_TEMPLATE_FIELD_VLAN, RTL931X_TEMPLATE_FIELD_ETHERTYPE, RTL931X_TEMPLATE_FIELD_IP_TOS_PROTO, - RTL931X_TEMPLATE_FIELD_SIP0, RTL931X_TEMPLATE_FIELD_SIP1, RTL931X_TEMPLATE_FIELD_DIP0, - RTL931X_TEMPLATE_FIELD_DIP1, RTL931X_TEMPLATE_FIELD_L4_SPORT, RTL931X_TEMPLATE_FIELD_L4_DPORT, - RTL931X_TEMPLATE_FIELD_META_DATA, RTL931X_TEMPLATE_FIELD_SLP - }, { - RTL931X_TEMPLATE_FIELD_DIP0, RTL931X_TEMPLATE_FIELD_DIP1, RTL931X_TEMPLATE_FIELD_DIP2, - RTL931X_TEMPLATE_FIELD_DIP3, RTL931X_TEMPLATE_FIELD_DIP4, RTL931X_TEMPLATE_FIELD_DIP5, - RTL931X_TEMPLATE_FIELD_DIP6, RTL931X_TEMPLATE_FIELD_DIP7, RTL931X_TEMPLATE_FIELD_IP_TOS_PROTO, - RTL931X_TEMPLATE_FIELD_TCP_INFO, RTL931X_TEMPLATE_FIELD_L4_SPORT, RTL931X_TEMPLATE_FIELD_L4_DPORT, - RTL931X_TEMPLATE_FIELD_RANGE_CHK, RTL931X_TEMPLATE_FIELD_SLP - }, { - RTL931X_TEMPLATE_FIELD_SIP0, RTL931X_TEMPLATE_FIELD_SIP1, RTL931X_TEMPLATE_FIELD_SIP2, - RTL931X_TEMPLATE_FIELD_SIP3, RTL931X_TEMPLATE_FIELD_SIP4, RTL931X_TEMPLATE_FIELD_SIP5, - RTL931X_TEMPLATE_FIELD_SIP6, RTL931X_TEMPLATE_FIELD_SIP7, RTL931X_TEMPLATE_FIELD_META_DATA, - RTL931X_TEMPLATE_FIELD_VLAN, RTL931X_TEMPLATE_FIELD_SPM0, RTL931X_TEMPLATE_FIELD_SPM1, - RTL931X_TEMPLATE_FIELD_SPM2, RTL931X_TEMPLATE_FIELD_SPM3 - }, -}; - const struct rtldsa_mib_list_item rtldsa_931x_mib_list[] = { MIB_LIST_ITEM("ifOutDiscards", MIB_ITEM(MIB_TBL_STD, 36, 1)), MIB_LIST_ITEM("dot1dTpPortInDiscards", MIB_ITEM(MIB_TBL_STD, 35, 1)), @@ -770,564 +681,6 @@ static int rtl931x_set_ageing_time(unsigned long msec) return 0; } -static void rtl931x_pie_lookup_enable(struct rtl838x_switch_priv *priv, int index) -{ - int block = index / PIE_BLOCK_SIZE; - - sw_w32_mask(0, BIT(block), RTL931X_PIE_BLK_LOOKUP_CTRL); -} - -/* Fills the data in the intermediate representation in the pie_rule structure - * into a data field for a given template field field_type - * TODO: This function looks very similar to the function of the rtl9300, but - * since it uses the physical template_field_id, which are different for each - * SoC and there are other field types, it is actually not. If we would also use - * an intermediate representation for a field type, we would could have one - * pie_data_fill function for all SoCs, provided we have also for each SoC a - * function to map between physical and intermediate field type - */ -static int rtl931x_pie_data_fill(enum rtl931x_template_field_id field_type, struct pie_rule *pr, u16 *data, u16 *data_m) -{ - *data = *data_m = 0; - - switch (field_type) { - case RTL931X_TEMPLATE_FIELD_SPM0: - *data = pr->spm; - *data_m = pr->spm_m; - break; - case RTL931X_TEMPLATE_FIELD_SPM1: - *data = pr->spm >> 16; - *data_m = pr->spm_m >> 16; - break; - case RTL931X_TEMPLATE_FIELD_OTAG: - *data = pr->otag; - *data_m = pr->otag_m; - break; - case RTL931X_TEMPLATE_FIELD_SMAC0: - *data = pr->smac[4]; - *data = (*data << 8) | pr->smac[5]; - *data_m = pr->smac_m[4]; - *data_m = (*data_m << 8) | pr->smac_m[5]; - break; - case RTL931X_TEMPLATE_FIELD_SMAC1: - *data = pr->smac[2]; - *data = (*data << 8) | pr->smac[3]; - *data_m = pr->smac_m[2]; - *data_m = (*data_m << 8) | pr->smac_m[3]; - break; - case RTL931X_TEMPLATE_FIELD_SMAC2: - *data = pr->smac[0]; - *data = (*data << 8) | pr->smac[1]; - *data_m = pr->smac_m[0]; - *data_m = (*data_m << 8) | pr->smac_m[1]; - break; - case RTL931X_TEMPLATE_FIELD_DMAC0: - *data = pr->dmac[4]; - *data = (*data << 8) | pr->dmac[5]; - *data_m = pr->dmac_m[4]; - *data_m = (*data_m << 8) | pr->dmac_m[5]; - break; - case RTL931X_TEMPLATE_FIELD_DMAC1: - *data = pr->dmac[2]; - *data = (*data << 8) | pr->dmac[3]; - *data_m = pr->dmac_m[2]; - *data_m = (*data_m << 8) | pr->dmac_m[3]; - break; - case RTL931X_TEMPLATE_FIELD_DMAC2: - *data = pr->dmac[0]; - *data = (*data << 8) | pr->dmac[1]; - *data_m = pr->dmac_m[0]; - *data_m = (*data_m << 8) | pr->dmac_m[1]; - break; - case RTL931X_TEMPLATE_FIELD_ETHERTYPE: - *data = pr->ethertype; - *data_m = pr->ethertype_m; - break; - case RTL931X_TEMPLATE_FIELD_ITAG: - *data = pr->itag; - *data_m = pr->itag_m; - break; - case RTL931X_TEMPLATE_FIELD_SIP0: - if (pr->is_ipv6) { - *data = pr->sip6.s6_addr16[7]; - *data_m = pr->sip6_m.s6_addr16[7]; - } else { - *data = pr->sip; - *data_m = pr->sip_m; - } - break; - case RTL931X_TEMPLATE_FIELD_SIP1: - if (pr->is_ipv6) { - *data = pr->sip6.s6_addr16[6]; - *data_m = pr->sip6_m.s6_addr16[6]; - } else { - *data = pr->sip >> 16; - *data_m = pr->sip_m >> 16; - } - break; - case RTL931X_TEMPLATE_FIELD_SIP2: - case RTL931X_TEMPLATE_FIELD_SIP3: - case RTL931X_TEMPLATE_FIELD_SIP4: - case RTL931X_TEMPLATE_FIELD_SIP5: - case RTL931X_TEMPLATE_FIELD_SIP6: - case RTL931X_TEMPLATE_FIELD_SIP7: - *data = pr->sip6.s6_addr16[5 - (field_type - RTL931X_TEMPLATE_FIELD_SIP2)]; - *data_m = pr->sip6_m.s6_addr16[5 - (field_type - RTL931X_TEMPLATE_FIELD_SIP2)]; - break; - case RTL931X_TEMPLATE_FIELD_DIP0: - if (pr->is_ipv6) { - *data = pr->dip6.s6_addr16[7]; - *data_m = pr->dip6_m.s6_addr16[7]; - } else { - *data = pr->dip; - *data_m = pr->dip_m; - } - break; - case RTL931X_TEMPLATE_FIELD_DIP1: - if (pr->is_ipv6) { - *data = pr->dip6.s6_addr16[6]; - *data_m = pr->dip6_m.s6_addr16[6]; - } else { - *data = pr->dip >> 16; - *data_m = pr->dip_m >> 16; - } - break; - case RTL931X_TEMPLATE_FIELD_DIP2: - case RTL931X_TEMPLATE_FIELD_DIP3: - case RTL931X_TEMPLATE_FIELD_DIP4: - case RTL931X_TEMPLATE_FIELD_DIP5: - case RTL931X_TEMPLATE_FIELD_DIP6: - case RTL931X_TEMPLATE_FIELD_DIP7: - *data = pr->dip6.s6_addr16[5 - (field_type - RTL931X_TEMPLATE_FIELD_DIP2)]; - *data_m = pr->dip6_m.s6_addr16[5 - (field_type - RTL931X_TEMPLATE_FIELD_DIP2)]; - break; - case RTL931X_TEMPLATE_FIELD_IP_TOS_PROTO: - *data = pr->tos_proto; - *data_m = pr->tos_proto_m; - break; - case RTL931X_TEMPLATE_FIELD_L4_SPORT: - *data = pr->sport; - *data_m = pr->sport_m; - break; - case RTL931X_TEMPLATE_FIELD_L4_DPORT: - *data = pr->dport; - *data_m = pr->dport_m; - break; - case RTL931X_TEMPLATE_FIELD_DSAP_SSAP: - *data = pr->dsap_ssap; - *data_m = pr->dsap_ssap_m; - break; - case RTL931X_TEMPLATE_FIELD_TCP_INFO: - *data = pr->tcp_info; - *data_m = pr->tcp_info_m; - break; - case RTL931X_TEMPLATE_FIELD_RANGE_CHK: - pr_debug("RTL931X_TEMPLATE_FIELD_RANGE_CHK: not configured\n"); - break; - default: - pr_debug("%s: unknown field %d\n", __func__, field_type); - return -1; - } - - return 0; -} - -/* Reads the intermediate representation of the templated match-fields of the - * PIE rule in the pie_rule structure and fills in the raw data fields in the - * raw register space r[]. - * The register space configuration size is identical for the RTL8380/90 and RTL9300, - * however the RTL931X has 2 more registers / fields and the physical field-ids are different - * on all SoCs - * On the RTL9300 the mask fields are not word-aligend! - */ -static void rtl931x_write_pie_templated(u32 r[], struct pie_rule *pr, enum rtl931x_template_field_id t[]) -{ - for (int i = 0; i < N_FIXED_FIELDS; i++) { - u16 data, data_m; - - rtl931x_pie_data_fill(t[i], pr, &data, &data_m); - - /* On the RTL9300, the mask fields are not word aligned! */ - if (!(i % 2)) { - r[5 - i / 2] = data; - r[12 - i / 2] |= ((u32)data_m << 8); - } else { - r[5 - i / 2] |= ((u32)data) << 16; - r[12 - i / 2] |= ((u32)data_m) << 24; - r[11 - i / 2] |= ((u32)data_m) >> 8; - } - } -} - -// Currently unused -// static void rtl931x_read_pie_fixed_fields(u32 r[], struct pie_rule *pr) -// { -// pr->mgnt_vlan = r[7] & BIT(31); -// if (pr->phase == PHASE_IACL) -// pr->dmac_hit_sw = r[7] & BIT(30); -// else /* TODO: EACL/VACL phase handling */ -// pr->content_too_deep = r[7] & BIT(30); -// pr->not_first_frag = r[7] & BIT(29); -// pr->frame_type_l4 = (r[7] >> 26) & 7; -// pr->frame_type = (r[7] >> 24) & 3; -// pr->otag_fmt = (r[7] >> 23) & 1; -// pr->itag_fmt = (r[7] >> 22) & 1; -// pr->otag_exist = (r[7] >> 21) & 1; -// pr->itag_exist = (r[7] >> 20) & 1; -// pr->frame_type_l2 = (r[7] >> 18) & 3; -// pr->igr_normal_port = (r[7] >> 17) & 1; -// pr->tid = (r[7] >> 16) & 1; - -// pr->mgnt_vlan_m = r[14] & BIT(15); -// if (pr->phase == PHASE_IACL) -// pr->dmac_hit_sw_m = r[14] & BIT(14); -// else -// pr->content_too_deep_m = r[14] & BIT(14); -// pr->not_first_frag_m = r[14] & BIT(13); -// pr->frame_type_l4_m = (r[14] >> 10) & 7; -// pr->frame_type_m = (r[14] >> 8) & 3; -// pr->otag_fmt_m = r[14] & BIT(7); -// pr->itag_fmt_m = r[14] & BIT(6); -// pr->otag_exist_m = r[14] & BIT(5); -// pr->itag_exist_m = r[14] & BIT (4); -// pr->frame_type_l2_m = (r[14] >> 2) & 3; -// pr->igr_normal_port_m = r[14] & BIT(1); -// pr->tid_m = r[14] & 1; - -// pr->valid = r[15] & BIT(31); -// pr->cond_not = r[15] & BIT(30); -// pr->cond_and1 = r[15] & BIT(29); -// pr->cond_and2 = r[15] & BIT(28); -// } - -static void rtl931x_write_pie_fixed_fields(u32 r[], struct pie_rule *pr) -{ - r[7] |= pr->mgnt_vlan ? BIT(31) : 0; - if (pr->phase == PHASE_IACL) - r[7] |= pr->dmac_hit_sw ? BIT(30) : 0; - else - r[7] |= pr->content_too_deep ? BIT(30) : 0; - r[7] |= pr->not_first_frag ? BIT(29) : 0; - r[7] |= ((u32)(pr->frame_type_l4 & 0x7)) << 26; - r[7] |= ((u32)(pr->frame_type & 0x3)) << 24; - r[7] |= pr->otag_fmt ? BIT(23) : 0; - r[7] |= pr->itag_fmt ? BIT(22) : 0; - r[7] |= pr->otag_exist ? BIT(21) : 0; - r[7] |= pr->itag_exist ? BIT(20) : 0; - r[7] |= ((u32)(pr->frame_type_l2 & 0x3)) << 18; - r[7] |= pr->igr_normal_port ? BIT(17) : 0; - r[7] |= ((u32)(pr->tid & 0x1)) << 16; - - r[14] |= pr->mgnt_vlan_m ? BIT(15) : 0; - if (pr->phase == PHASE_IACL) - r[14] |= pr->dmac_hit_sw_m ? BIT(14) : 0; - else - r[14] |= pr->content_too_deep_m ? BIT(14) : 0; - r[14] |= pr->not_first_frag_m ? BIT(13) : 0; - r[14] |= ((u32)(pr->frame_type_l4_m & 0x7)) << 10; - r[14] |= ((u32)(pr->frame_type_m & 0x3)) << 8; - r[14] |= pr->otag_fmt_m ? BIT(7) : 0; - r[14] |= pr->itag_fmt_m ? BIT(6) : 0; - r[14] |= pr->otag_exist_m ? BIT(5) : 0; - r[14] |= pr->itag_exist_m ? BIT(4) : 0; - r[14] |= ((u32)(pr->frame_type_l2_m & 0x3)) << 2; - r[14] |= pr->igr_normal_port_m ? BIT(1) : 0; - r[14] |= (u32)(pr->tid_m & 0x1); - - r[15] |= pr->valid ? BIT(31) : 0; - r[15] |= pr->cond_not ? BIT(30) : 0; - r[15] |= pr->cond_and1 ? BIT(29) : 0; - r[15] |= pr->cond_and2 ? BIT(28) : 0; -} - -static void rtl931x_write_pie_action(u32 r[], struct pie_rule *pr) -{ - /* Either drop or forward */ - if (pr->drop) { - r[15] |= BIT(11) | BIT(12) | BIT(13); /* Do Green, Yellow and Red drops */ - /* Actually DROP, not PERMIT in Green / Yellow / Red */ - r[16] |= BIT(27) | BIT(28) | BIT(29); - } else { - r[15] |= pr->fwd_sel ? BIT(14) : 0; - r[16] |= pr->fwd_act << 24; - r[16] |= BIT(21); /* We overwrite any drop */ - } - if (pr->phase == PHASE_VACL) - r[16] |= pr->fwd_sa_lrn ? BIT(22) : 0; - r[15] |= pr->bypass_sel ? BIT(10) : 0; - r[15] |= pr->nopri_sel ? BIT(21) : 0; - r[15] |= pr->tagst_sel ? BIT(20) : 0; - r[15] |= pr->ovid_sel ? BIT(18) : 0; - r[15] |= pr->ivid_sel ? BIT(16) : 0; - r[15] |= pr->meter_sel ? BIT(27) : 0; - r[15] |= pr->mir_sel ? BIT(15) : 0; - r[15] |= pr->log_sel ? BIT(26) : 0; - - r[16] |= ((u32)(pr->fwd_data & 0xfff)) << 9; -/* r[15] |= pr->log_octets ? BIT(31) : 0; */ - r[15] |= (u32)(pr->meter_data) >> 2; - r[16] |= (((u32)(pr->meter_data) >> 7) & 0x3) << 29; - - r[16] |= ((u32)(pr->ivid_act & 0x3)) << 21; - r[15] |= ((u32)(pr->ivid_data & 0xfff)) << 9; - r[16] |= ((u32)(pr->ovid_act & 0x3)) << 30; - r[16] |= ((u32)(pr->ovid_data & 0xfff)) << 16; - r[16] |= ((u32)(pr->mir_data & 0x3)) << 6; - r[17] |= ((u32)(pr->tagst_data & 0xf)) << 28; - r[17] |= ((u32)(pr->nopri_data & 0x7)) << 25; - r[17] |= pr->bypass_ibc_sc ? BIT(16) : 0; -} - -static void rtl931x_pie_rule_dump_raw(u32 r[]) -{ - pr_debug("Raw IACL table entry:\n"); - pr_debug("r 0 - 7: %08x %08x %08x %08x %08x %08x %08x %08x\n", - r[0], r[1], r[2], r[3], r[4], r[5], r[6], r[7]); - pr_debug("r 8 - 15: %08x %08x %08x %08x %08x %08x %08x %08x\n", - r[8], r[9], r[10], r[11], r[12], r[13], r[14], r[15]); - pr_debug("r 16 - 18: %08x %08x %08x\n", r[16], r[17], r[18]); - pr_debug("Match : %08x %08x %08x %08x %08x %08x\n", r[0], r[1], r[2], r[3], r[4], r[5]); - pr_debug("Fixed : %06x\n", r[6] >> 8); - pr_debug("Match M: %08x %08x %08x %08x %08x %08x\n", - (r[6] << 24) | (r[7] >> 8), (r[7] << 24) | (r[8] >> 8), (r[8] << 24) | (r[9] >> 8), - (r[9] << 24) | (r[10] >> 8), (r[10] << 24) | (r[11] >> 8), - (r[11] << 24) | (r[12] >> 8)); - pr_debug("R[13]: %08x\n", r[13]); - pr_debug("Fixed M: %06x\n", ((r[12] << 16) | (r[13] >> 16)) & 0xffffff); - pr_debug("Valid / not / and1 / and2 : %1x\n", (r[13] >> 12) & 0xf); - pr_debug("r 13-16: %08x %08x %08x %08x\n", r[13], r[14], r[15], r[16]); -} - -static int rtl931x_pie_rule_write(struct rtl838x_switch_priv *priv, int idx, struct pie_rule *pr) -{ - int tbl = otto_table_acquire(RTL9310_TBL_IACL); - u32 r[22]; - int block = idx / PIE_BLOCK_SIZE; - u32 t_select = sw_r32(RTL931X_PIE_BLK_TMPLTE_CTRL(block)); - - pr_debug("%s: %d, t_select: %08x\n", __func__, idx, t_select); - - for (int i = 0; i < 22; i++) - r[i] = 0; - - if (!pr->valid) { - __otto_table_write(tbl, idx, &r); - otto_table_release(tbl); - return 0; - } - rtl931x_write_pie_fixed_fields(r, pr); - - pr_debug("%s: template %d\n", __func__, (t_select >> (pr->tid * 4)) & 0xf); - rtl931x_write_pie_templated(r, pr, rtl931x_fixed_templates[(t_select >> (pr->tid * 4)) & 0xf]); - - rtl931x_write_pie_action(r, pr); - - rtl931x_pie_rule_dump_raw(r); - - __otto_table_write(tbl, idx, &r); - otto_table_release(tbl); - - return 0; -} - -static bool rtl931x_pie_templ_has(int t, enum rtl931x_template_field_id field_type) -{ - for (int i = 0; i < N_FIXED_FIELDS_RTL931X; i++) { - enum rtl931x_template_field_id ft = rtl931x_fixed_templates[t][i]; - - if (field_type == ft) - return true; - } - - return false; -} - -/* Verify that the rule pr is compatible with a given template t in block - * Note that this function is SoC specific since the values of e.g. RTL931X_TEMPLATE_FIELD_SIP0 - * depend on the SoC - */ -static int rtl931x_pie_verify_template(struct rtl838x_switch_priv *priv, - struct pie_rule *pr, int t, int block) -{ - int i; - - if (!pr->is_ipv6 && pr->sip_m && !rtl931x_pie_templ_has(t, RTL931X_TEMPLATE_FIELD_SIP0)) - return -1; - - if (!pr->is_ipv6 && pr->dip_m && !rtl931x_pie_templ_has(t, RTL931X_TEMPLATE_FIELD_DIP0)) - return -1; - - if (pr->is_ipv6) { - if ((pr->sip6_m.s6_addr32[0] || - pr->sip6_m.s6_addr32[1] || - pr->sip6_m.s6_addr32[2] || - pr->sip6_m.s6_addr32[3]) && - !rtl931x_pie_templ_has(t, RTL931X_TEMPLATE_FIELD_SIP2)) - return -1; - if ((pr->dip6_m.s6_addr32[0] || - pr->dip6_m.s6_addr32[1] || - pr->dip6_m.s6_addr32[2] || - pr->dip6_m.s6_addr32[3]) && - !rtl931x_pie_templ_has(t, RTL931X_TEMPLATE_FIELD_DIP2)) - return -1; - } - - if (ether_addr_to_u64(pr->smac_m) && !rtl931x_pie_templ_has(t, RTL931X_TEMPLATE_FIELD_SMAC0)) - return -1; - - if (ether_addr_to_u64(pr->dmac_m) && !rtl931x_pie_templ_has(t, RTL931X_TEMPLATE_FIELD_DMAC0)) - return -1; - - if (pr->itag_m && !rtl931x_pie_templ_has(t, RTL931X_TEMPLATE_FIELD_VLAN)) - return -1; - - if (pr->sport_m && !rtl931x_pie_templ_has(t, RTL931X_TEMPLATE_FIELD_L4_SPORT)) - return -1; - - if (pr->dport_m && !rtl931x_pie_templ_has(t, RTL931X_TEMPLATE_FIELD_L4_DPORT)) - return -1; - - /* TODO: Check more */ - - i = find_first_zero_bit(&priv->pie_use_bm[block * 4], PIE_BLOCK_SIZE); - - if (i >= PIE_BLOCK_SIZE) - return -1; - - return i + PIE_BLOCK_SIZE * block; -} - -static int rtl931x_pie_rule_add(struct rtl838x_switch_priv *priv, struct pie_rule *pr) -{ - int idx, block, j; - int min_block = 0; - int max_block = priv->r->n_pie_blocks / 2; - - if (pr->is_egress) { - min_block = max_block; - max_block = priv->r->n_pie_blocks; - } - pr_debug("In %s\n", __func__); - - mutex_lock(&priv->pie_mutex); - - for (block = min_block; block < max_block; block++) { - for (j = 0; j < 2; j++) { - int t = (sw_r32(RTL931X_PIE_BLK_TMPLTE_CTRL(block)) >> (j * 4)) & 0xf; - - pr_debug("Testing block %d, template %d, template id %d\n", block, j, t); - pr_debug("%s: %08x\n", - __func__, sw_r32(RTL931X_PIE_BLK_TMPLTE_CTRL(block))); - idx = rtl931x_pie_verify_template(priv, pr, t, block); - if (idx >= 0) - break; - } - if (j < 2) - break; - } - - if (block >= max_block) { - mutex_unlock(&priv->pie_mutex); - return -EOPNOTSUPP; - } - - pr_debug("Using block: %d, index %d, template-id %d\n", block, idx, j); - set_bit(idx, priv->pie_use_bm); - - pr->valid = true; - pr->tid = j; /* Mapped to template number */ - pr->tid_m = 0x1; - pr->id = idx; - - rtl931x_pie_lookup_enable(priv, idx); - rtl931x_pie_rule_write(priv, idx, pr); - - mutex_unlock(&priv->pie_mutex); - - return 0; -} - -/* Delete a range of Packet Inspection Engine rules */ -static int rtl931x_pie_rule_del(struct rtl838x_switch_priv *priv, int index_from, int index_to) -{ - u32 v = (index_from << 1) | (index_to << 13) | BIT(0); - - pr_debug("%s: from %d to %d\n", __func__, index_from, index_to); - mutex_lock(&priv->reg_mutex); - - /* Write from-to and execute bit into control register */ - sw_w32(v, RTL931X_PIE_CLR_CTRL); - - /* Wait until command has completed */ - do { - } while (sw_r32(RTL931X_PIE_CLR_CTRL) & BIT(0)); - - mutex_unlock(&priv->reg_mutex); - - return 0; -} - -static void rtl931x_pie_rule_rm(struct rtl838x_switch_priv *priv, struct pie_rule *pr) -{ - int idx = pr->id; - - rtl931x_pie_rule_del(priv, idx, idx); - clear_bit(idx, priv->pie_use_bm); -} - -static void rtl931x_pie_init(struct rtl838x_switch_priv *priv) -{ - u32 template_selectors; - - mutex_init(&priv->pie_mutex); - - pr_debug("%s\n", __func__); - /* Enable ACL lookup on all ports, including CPU_PORT */ - for (int i = 0; i <= priv->r->cpu_port; i++) - sw_w32(1, RTL931X_ACL_PORT_LOOKUP_CTRL(i)); - - /* Include IPG in metering */ - sw_w32_mask(0, 1, RTL931X_METER_GLB_CTRL); - - /* Delete all present rules, block size is 128 on all SoC families */ - rtl931x_pie_rule_del(priv, 0, priv->r->n_pie_blocks * 128 - 1); - - /* Assign first half blocks 0-7 to VACL phase, second half to IACL */ - /* 3 bits are used for each block, values for PIE blocks are */ - /* 6: Disabled, 0: VACL, 1: IACL, 2: EACL */ - /* And for OpenFlow Flow blocks: 3: Ingress Flow table 0, */ - /* 4: Ingress Flow Table 3, 5: Egress flow table 0 */ - for (int i = 0; i < priv->r->n_pie_blocks; i++) { - int pos = (i % 10) * 3; - u32 r = RTL931X_PIE_BLK_PHASE_CTRL + 4 * (i / 10); - - if (i < priv->r->n_pie_blocks / 2) - sw_w32_mask(0x7 << pos, 0, r); - else - sw_w32_mask(0x7 << pos, 1 << pos, r); - } - - /* Enable predefined templates 0, 1 for first quarter of all blocks */ - template_selectors = 0 | (1 << 4); - for (int i = 0; i < priv->r->n_pie_blocks / 4; i++) - sw_w32(template_selectors, RTL931X_PIE_BLK_TMPLTE_CTRL(i)); - - /* Enable predefined templates 2, 3 for second quarter of all blocks */ - template_selectors = 2 | (3 << 4); - for (int i = priv->r->n_pie_blocks / 4; i < priv->r->n_pie_blocks / 2; i++) - sw_w32(template_selectors, RTL931X_PIE_BLK_TMPLTE_CTRL(i)); - - /* Enable predefined templates 0, 1 for third quater of all blocks */ - template_selectors = 0 | (1 << 4); - for (int i = priv->r->n_pie_blocks / 2; i < priv->r->n_pie_blocks * 3 / 4; i++) - sw_w32(template_selectors, RTL931X_PIE_BLK_TMPLTE_CTRL(i)); - - /* Enable predefined templates 2, 3 for fourth quater of all blocks */ - template_selectors = 2 | (3 << 4); - for (int i = priv->r->n_pie_blocks * 3 / 4; i < priv->r->n_pie_blocks; i++) - sw_w32(template_selectors, RTL931X_PIE_BLK_TMPLTE_CTRL(i)); -} - static int rtldsa_931x_fast_age(struct rtl838x_switch_priv *priv, int port, int vid) { u32 val;