From nobody Mon Jun 8 14:35:32 2026 Received: from mail-pf1-f173.google.com (mail-pf1-f173.google.com [209.85.210.173]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 2B7BF352004 for ; Thu, 28 May 2026 19:40:16 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.210.173 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1779997218; cv=none; b=Jcr3HiFKINYRJ1Pv2sVTR2Uc5gw277zs9K7QNRSF2BAoJP09CoASg+wJH/u6RMggGhYMqzYN8xOAVEx37IHfpyCCf/LDIGUXOlBkbDZsm/D4rLLw+BGhlFptKjTqND6RjC+f+N9D712URkJUw9LrO+Be0AufbE2BcYCwDWIUNpM= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1779997218; c=relaxed/simple; bh=pRgco4WNNdgR8495tajkq9qSwa/BIpevqW2Y2olzEAs=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=NKygMvrEW53kFc0ihzJ7PiyVsQAqBx1328FX6kDFmYHhgKV8Dl+wvHWg1xVPPAPFjvMZ9i9YJLe9527A9OrewdIAgmTheh1ZQTtQCTz6/S40zApLqxT2nAKAbhAeJQFUMtfdyDjO3UnlBwrNPqo6BE0ubYpLeSrDfjM1WlZE7FQ= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=SHH09aO+; arc=none smtp.client-ip=209.85.210.173 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="SHH09aO+" Received: by mail-pf1-f173.google.com with SMTP id d2e1a72fcca58-83975e992e1so5429206b3a.2 for ; Thu, 28 May 2026 12:40:16 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1779997216; x=1780602016; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=0v1mafeerf+0c330SrsP+aoq+1EhfoexoEg8eIBj6Kg=; b=SHH09aO+cEPXinP8Muy9jz/pCiJE4tk2tZWPnssEYcSHTbAl8MqRzYV0eQEh7CMppm /fKJwfWt0W0uV6/RVaPtJ2AkzLfHYVbetnv7u0L0hTaXbVuDVQuCsi8z+qEgHZT6k7Ps MTJioxo/M2t+OCGr4FnE3OE7eWuIe55ZcOiOJ7ZGg1vvc1xlw+nfcfYKzW5b6+ZXG9Ng PA9GHodpszJ5GUNjWkMV2JuP+C/gtyJmBHvygC9582HryjM+9e6sDxLgq7u+opPsDNa7 y/KAFdmvtPNOHh5GrXBcO08/vUmaG1JSz+7Jp6M1ZwSpww5J6UgqiVTBgvsGydo15y+1 r+fg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1779997216; x=1780602016; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=0v1mafeerf+0c330SrsP+aoq+1EhfoexoEg8eIBj6Kg=; b=j98M/8nyXhvZ6FEQoMxCWG43WXgNCZ5WEQwNBHdls8XiA5FozHNP+5/iMh5semvM3p l/o1i5K7QMjt2PUrBZHlqYBFL3tYM2SSMil4WblXzDOm22oVRxFCD10R4Y2aAeyWAXxT 4+Z4X2mhGkLSsghNbsoMTDuSMT3GIAaazuuN66v2iOYVJmZnkwW3DPl1h8GeMW6qv6fj HM93X1X796UTxvU2DF8+T499RU84uxna3UGlgii+Ro6mpgfbw3vjLJO4sUPWubOrtlSo 4kcMPO7BB/Tjmbl9RBZGMSkzigVAOsAu6IStPii9fdqP89i9dA2fWL4pQHnJtuNnerFV 0CVw== X-Forwarded-Encrypted: i=1; AFNElJ+tBSWV8e3Uecj752N8uxlx3pCyDvz2OwqwyYtA5oSeGbIt/Oe4DszcPWnZG83241yXhCr/RvSjzH/MbME=@vger.kernel.org X-Gm-Message-State: AOJu0YyqLlFh1essCRyHkVDlZ6gxc/YEWddnjSS3vmu1Gy1GQrFk80xO bI42wYho9ZYg+UJ7A5nmA+/XBW6wNP3HseOx6/YvUxA1IjwLXG8/mQr9 X-Gm-Gg: Acq92OG4AcMsHlRPY7aAaR2azMtwYOQSfqvUyANSHF48CK8WPD9GcvyIOdtwa/COLay ueeFqdZtmuCcwyP2sQlBAQXfOc9bi78+7vai5FCUxD4nA0/X6JvCyLPr5+RpGE07SU6/+Vq+irS MSySnHIoeJo+h9+50IK2x4JG/V+/v5D5HQ1E/mereNt6yhon1QmybZThtIAceB69bCg3Pc/peZB b0ImnlPXdo1xq06wkK8m+HHRfxXRlcfbFxzV/xTHEJRsvauG+tssNn6B+ISa1M7sei24A6Dx7RT bIWl3GgWceBODEEoUhtf7BzkyiL3xlkBz67JHKgK1ZVrzz2e7b9VXlpsQNtALY1cVTcizQqZ7Pt Nkn+kf+b7/DUXYRZxl9U65G0MwhTTkveCm6wBdI30S11oA4QwV+GDLfPXZQi0ZLq4UeUArtmFW7 5erSfBmv2l7N4P9lcNljcdGaX+9yBP2pPRzl8q1AEyP3XUHoT6WvBJexi3P8JsD+oqu4I3WMFG X-Received: by 2002:a05:6a00:9298:b0:841:71fd:60c4 with SMTP id d2e1a72fcca58-8420c27c5f3mr415125b3a.4.1779997216263; Thu, 28 May 2026 12:40:16 -0700 (PDT) Received: from d.home.yangfl.dn42 ([104.28.215.164]) by smtp.gmail.com with ESMTPSA id d2e1a72fcca58-841d6eac68esm5900184b3a.15.2026.05.28.12.40.13 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 28 May 2026 12:40:15 -0700 (PDT) From: David Yang To: netdev@vger.kernel.org Cc: David Yang , Andrew Lunn , Vladimir Oltean , "David S. Miller" , Eric Dumazet , Jakub Kicinski , Paolo Abeni , Simon Horman , linux-kernel@vger.kernel.org Subject: [PATCH net-next v4 1/2] net: dsa: tag_yt921x: handle ACL tag code Date: Fri, 29 May 2026 03:37:18 +0800 Message-ID: <20260528193726.1893365-2-mmyangfl@gmail.com> X-Mailer: git-send-email 2.53.0 In-Reply-To: <20260528193726.1893365-1-mmyangfl@gmail.com> References: <20260528193726.1893365-1-mmyangfl@gmail.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" This prepares for upcoming ACL features that use forward redirection in ACL rules. Signed-off-by: David Yang --- net/dsa/tag_yt921x.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/net/dsa/tag_yt921x.c b/net/dsa/tag_yt921x.c index aefef8c770e3..f3ced99b1c85 100644 --- a/net/dsa/tag_yt921x.c +++ b/net/dsa/tag_yt921x.c @@ -49,6 +49,7 @@ */ enum yt921x_tag_code { YT921X_TAG_CODE_FORWARD =3D 0, + YT921X_TAG_CODE_ACL =3D 0x17, YT921X_TAG_CODE_UNK_UCAST =3D 0x19, YT921X_TAG_CODE_UNK_MCAST =3D 0x1a, YT921X_TAG_CODE_PORT_COPY =3D 0x1b, @@ -129,6 +130,7 @@ yt921x_tag_rcv(struct sk_buff *skb, struct net_device *= netdev) /* Already forwarded by hardware */ dsa_default_offload_fwd_mark(skb); break; + case YT921X_TAG_CODE_ACL: case YT921X_TAG_CODE_UNK_UCAST: case YT921X_TAG_CODE_UNK_MCAST: /* NOTE: hardware doesn't distinguish between TRAP (copy --=20 2.53.0 From nobody Mon Jun 8 14:35:32 2026 Received: from mail-pf1-f177.google.com (mail-pf1-f177.google.com [209.85.210.177]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 857D040910B for ; Thu, 28 May 2026 19:40:20 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.210.177 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1779997223; cv=none; b=IfTNnxBdw2je+Nb5lDnATf3Wb6BulrlPexq9olORYHPudgzThLZUyIyKpbRNgZpbOULarHYFzrVfiyCOOQXhAl8y9fb0A6vyWwwt93E9I6UWwQy8zJ0NBh97l6wuHO8hoPaRsEf5MbN3bWcyPSBaRSfHo74pJaGZj2JcyZnOvJw= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1779997223; c=relaxed/simple; bh=hLXXyBcXsyrMsBB00KDcMwHR8mBpRgN1+pp+evP4bDY=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=DlAPol3AGNwC0V5HFYT6amlhqFNICgYuWQZbTeXr570GY/dKxMBalnqQh6ZFY0VnJxQ6vyTEed1KuBb5viEiimR6xZ2TdyPtUB18u2D/L1UlCGnfkwAVnnAq/4wtfP642Zmsy9Fi0s2lggUxikfZVjcIfHAxvd5BrKDEtK2L1e4= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=ipyCD6dt; arc=none smtp.client-ip=209.85.210.177 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="ipyCD6dt" Received: by mail-pf1-f177.google.com with SMTP id d2e1a72fcca58-841513664bbso4119280b3a.1 for ; Thu, 28 May 2026 12:40:20 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1779997220; x=1780602020; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=aLwRW6L4tnM+7RWiYBacdSgOpum8LZiunqIahR5hN5o=; b=ipyCD6dtrlOA4cQ72yc2yvGoRZFWayUVO5ukTeFeqPSVOW+xbZwG7NsUdjk0/AiioQ T7A1/qK/qGhHlnSLK7H2HuxZwybdQjsHUvSD7ksI/gFX8zxYdD859hZP/YzAI8FIbwtd 0vpkZsq1RuQMiKLETV3WWE6XHpuRkYW3u4LB5T/gQC7djsVj7PL7EnMhIQI/mLLOKPSu 93y2G5qd1s2McREP31binjmRX8IwI/l3EMKbAJ4Y4ZbbD5fteA5YCNgXQSQ+48KfZgjd L8NJCjy+bVWeIjY2nn4qJZ1jiSEjmh1RzH01CaJippwTyhSJueJdU3aGGURPxA6oCLXF ke8A== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1779997220; x=1780602020; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=aLwRW6L4tnM+7RWiYBacdSgOpum8LZiunqIahR5hN5o=; b=i1fG3wvT5CKSIcfjoRhquObB+QkliClVNeZQvbV+xu09/Cis3MD2Akwc1pjL9kh611 jxw5FoYEWuCCrUxxXSjbMiEyMSzKiYn/51VuQjgR9MdtxrGOSHss+ud5pwZIFXv/NO9m hbyvMihuJH4yqNM22L09gF9RrRJaT/xSYY3AcYX3wDzNAt5cREOzlGL+gHbyAP7yJEyw rG7SEbweYTXSmutlsVtYEtum2hSxgBftCo0CKHx/rsAczDjPgF5VBV0F7jNtZhAj2icw g2l58w5OVoMwM9z8f+1K75jb03ktgkDagP+mXXkh6mBigkxKOmklsuhpISWWXMNmXgir g06w== X-Forwarded-Encrypted: i=1; AFNElJ/L0s69DKPqz57ifa6P98qzySOtcO/7xq2K9w6eLX5UV3EbZhgtDnFj3BdW6r1TaZpQ1a7QWteMJu31PR4=@vger.kernel.org X-Gm-Message-State: AOJu0YyRFecT3rvvrZEJ17OLYcTF8m6k5k+xAjWvdIlLiQGjtJUm5OYw 0bnIoXQtYuNB4mlkrnv/o6lspRa6bA5rBmI6rV+o3P/VhbF4X7DxaW4X X-Gm-Gg: Acq92OGqRHhJ/zNkosqKKqGQ07XgrMKN45f7BKBHz6ZCK8tHNUy2hct1g+657pRFUzp 3OoiL9hUhS/0thnzuOAF0vdNwJIuYz6MnFo1qi3sDCVhu0UYx4vJVfTU6yGpn00AUmHl3DAAMvj x2efpaQy5JZyZUyOypuHr5GXh9fS6h8T7j90qQ/+5Q5NVQMvU07MBeRRR5sMSmYgI8JAzYf8Qnf x7+B/fU9stlMTjteyxqSx9OQcPe+ueOHbuNvLiWZAzjJvgebmkestEDKFBkdBakfPlFyUQUQhg/ Fk+D7F3br4DvNWVISio3AJ5jnz2lW7m8EYzVKe57bgQq7crHIrqpaEAAAaFAMgA3d0L6kZUUqm6 IcuQemNyJaWkdo+7aEz4HDr1WBkAEWgA6n4z1QTkkmAsfs3KXZB7C0mopPATWZXy2RZ8ms7RcaS aGNQghX6ET9/diJ6nCvVfUJWb0xW9bRLHQ/SokJmWkzytGU1XbBFStYZKv36Q0dpL7IEWrjEeaw f4BCOltbwo= X-Received: by 2002:a05:6a00:14c5:b0:82f:6aee:7d5c with SMTP id d2e1a72fcca58-8420f396045mr29032b3a.9.1779997219684; Thu, 28 May 2026 12:40:19 -0700 (PDT) Received: from d.home.yangfl.dn42 ([104.28.215.164]) by smtp.gmail.com with ESMTPSA id d2e1a72fcca58-841d6eac68esm5900184b3a.15.2026.05.28.12.40.16 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 28 May 2026 12:40:19 -0700 (PDT) From: David Yang To: netdev@vger.kernel.org Cc: David Yang , Andrew Lunn , Vladimir Oltean , "David S. Miller" , Eric Dumazet , Jakub Kicinski , Paolo Abeni , Simon Horman , linux-kernel@vger.kernel.org, hong son Nguyen Subject: [PATCH net-next v4 2/2] net: dsa: yt921x: Add ACL support Date: Fri, 29 May 2026 03:37:19 +0800 Message-ID: <20260528193726.1893365-3-mmyangfl@gmail.com> X-Mailer: git-send-email 2.53.0 In-Reply-To: <20260528193726.1893365-1-mmyangfl@gmail.com> References: <20260528193726.1893365-1-mmyangfl@gmail.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Enable filtering of incoming traffics. Note that custom filters are yet to be utilized, and thus not all flow dissectors are implemented. Tested-by: hong son Nguyen Signed-off-by: David Yang --- drivers/net/dsa/yt921x.c | 1013 +++++++++++++++++++++++++++++++++++++- drivers/net/dsa/yt921x.h | 284 +++++++++++ 2 files changed, 1294 insertions(+), 3 deletions(-) diff --git a/drivers/net/dsa/yt921x.c b/drivers/net/dsa/yt921x.c index 9cc211b90c6c..d8c55139c020 100644 --- a/drivers/net/dsa/yt921x.c +++ b/drivers/net/dsa/yt921x.c @@ -186,6 +186,16 @@ struct yt921x_reg_mdio { #define to_yt921x_priv(_ds) container_of_const(_ds, struct yt921x_priv, ds) #define to_device(priv) ((priv)->ds.dev) =20 +static u32 ethaddr_hi4_to_u32(const unsigned char *addr) +{ + return (addr[0] << 24) | (addr[1] << 16) | (addr[2] << 8) | addr[3]; +} + +static u32 ethaddr_lo2_to_u32(const unsigned char *addr) +{ + return (addr[4] << 8) | addr[5]; +} + static int yt921x_reg_read(struct yt921x_priv *priv, u32 reg, u32 *valp) { WARN_ON(!mutex_is_locked(&priv->reg_lock)); @@ -1457,6 +1467,978 @@ yt921x_dsa_port_setup_tc(struct dsa_switch *ds, int= port, } } =20 +/* ACL: 48 blocks * 8 entries + * + * One rule can span multiple entries, but within a block. + */ + +static void +yt921x_acl_entry_set(struct yt921x_acl_entry *entry, unsigned int offset, + u32 flags, bool set) +{ + if (set) + entry->key[offset] |=3D flags; + entry->mask[offset] |=3D flags; +} + +static unsigned int +yt921x_acl_entries_set_first_frag(struct yt921x_acl_entry *entries, + unsigned int size, bool set) +{ + for (unsigned int i =3D 0; i < size; i++) + switch (FIELD_GET(YT921X_ACL_KEYb_TYPE_M, entries[i].key[1])) { + case YT921X_ACL_TYPE_IPV6_DA2: + case YT921X_ACL_TYPE_IPV6_SA2: + yt921x_acl_entry_set(&entries[i], 1, + YT921X_ACL_BINb_IPV6_xA2_FIRST_FRAG, + set); + return size; + case YT921X_ACL_TYPE_MISC: + yt921x_acl_entry_set(&entries[i], 0, + YT921X_ACL_BINa_MISC_FIRST_FRAG, + set); + return size; + } + + if (size >=3D YT921X_ACL_ENT_PER_BLK) + return 0; + + entries[size] =3D (typeof(*entries)){}; + entries[size].key[1] =3D YT921X_ACL_KEYb_TYPE(YT921X_ACL_TYPE_MISC); + yt921x_acl_entry_set(&entries[size], 0, + YT921X_ACL_BINa_MISC_FIRST_FRAG, set); + + return size + 1; +} + +static unsigned int +yt921x_acl_entries_set_is_fragment(struct yt921x_acl_entry *entries, + unsigned int size, bool set) +{ + for (unsigned int i =3D 0; i < size; i++) + switch (FIELD_GET(YT921X_ACL_KEYb_TYPE_M, entries[i].key[1])) { + case YT921X_ACL_TYPE_IPV4_DA: + case YT921X_ACL_TYPE_IPV4_SA: + yt921x_acl_entry_set(&entries[i], 1, + YT921X_ACL_BINb_IPV4_FRAG, set); + return size; + case YT921X_ACL_TYPE_IPV6_DA3: + case YT921X_ACL_TYPE_IPV6_SA3: + yt921x_acl_entry_set(&entries[i], 1, + YT921X_ACL_BINb_IPV6_xA3_FRAG, + set); + return size; + case YT921X_ACL_TYPE_MISC: + yt921x_acl_entry_set(&entries[i], 1, + YT921X_ACL_BINb_MISC_FRAG, set); + return size; + case YT921X_ACL_TYPE_L4: + yt921x_acl_entry_set(&entries[i], 1, + YT921X_ACL_BINb_L4_FRAG, set); + return size; + } + + if (size >=3D YT921X_ACL_ENT_PER_BLK) + return 0; + + entries[size] =3D (typeof(*entries)){}; + entries[size].key[1] =3D YT921X_ACL_KEYb_TYPE(YT921X_ACL_TYPE_MISC); + yt921x_acl_entry_set(&entries[size], 1, YT921X_ACL_BINb_MISC_FRAG, set); + + return size + 1; +} + +static unsigned int +yt921x_acl_entries_set_l3_type(struct yt921x_acl_entry *entries, + unsigned int size, enum yt921x_l3_type type) +{ + for (unsigned int i =3D 0; i < size; i++) + switch (FIELD_GET(YT921X_ACL_KEYb_TYPE_M, entries[i].key[1])) { + case YT921X_ACL_TYPE_MAC_DA0: + case YT921X_ACL_TYPE_MAC_SA0: + entries[i].key[1] |=3D YT921X_ACL_BINb_MAC_xA0_L3_TYPE(type); + entries[i].mask[1] |=3D YT921X_ACL_BINb_MAC_xA0_L3_TYPE_M; + return size; + case YT921X_ACL_TYPE_MISC: + entries[i].key[0] |=3D YT921X_ACL_BINa_MISC_L3_TYPE(type); + entries[i].mask[0] |=3D YT921X_ACL_BINa_MISC_L3_TYPE_M; + return size; + } + + if (size >=3D YT921X_ACL_ENT_PER_BLK) + return 0; + + entries[size] =3D (typeof(*entries)){}; + entries[size].key[0] =3D YT921X_ACL_BINa_MISC_L3_TYPE(type); + entries[size].key[1] =3D YT921X_ACL_KEYb_TYPE(YT921X_ACL_TYPE_MISC); + entries[size].mask[0] =3D YT921X_ACL_BINa_MISC_L3_TYPE_M; + + return size + 1; +} + +static unsigned int +yt921x_acl_entries_set_l4_type(struct yt921x_acl_entry *entries, + unsigned int size, enum yt921x_l4_type type) +{ + for (unsigned int i =3D 0; i < size; i++) + switch (FIELD_GET(YT921X_ACL_KEYb_TYPE_M, entries[i].key[1])) { + case YT921X_ACL_TYPE_IPV4_DA: + case YT921X_ACL_TYPE_IPV4_SA: + entries[i].key[1] |=3D YT921X_ACL_BINb_IPV4_L4_TYPE(type); + entries[i].mask[1] |=3D YT921X_ACL_BINb_IPV4_L4_TYPE_M; + return size; + case YT921X_ACL_TYPE_IPV6_DA0: + case YT921X_ACL_TYPE_IPV6_DA1: + case YT921X_ACL_TYPE_IPV6_DA2: + case YT921X_ACL_TYPE_IPV6_DA3: + case YT921X_ACL_TYPE_IPV6_SA0: + case YT921X_ACL_TYPE_IPV6_SA1: + case YT921X_ACL_TYPE_IPV6_SA2: + case YT921X_ACL_TYPE_IPV6_SA3: + entries[i].key[1] |=3D YT921X_ACL_BINb_IPV6_L4_TYPE(type); + entries[i].mask[1] |=3D YT921X_ACL_BINb_IPV6_L4_TYPE_M; + return size; + case YT921X_ACL_TYPE_L4: + entries[i].key[1] |=3D YT921X_ACL_BINb_L4_TYPE(type); + entries[i].mask[1] |=3D YT921X_ACL_BINb_L4_TYPE_M; + return size; + case YT921X_ACL_TYPE_MISC: + entries[i].key[1] |=3D YT921X_ACL_BINb_MISC_L4_TYPE(type); + entries[i].mask[1] |=3D YT921X_ACL_BINb_MISC_L4_TYPE_M; + return size; + } + + if (size >=3D YT921X_ACL_ENT_PER_BLK) + return 0; + + entries[size] =3D (typeof(*entries)){}; + entries[size].key[1] =3D YT921X_ACL_BINb_MISC_L4_TYPE(type) | + YT921X_ACL_KEYb_TYPE(YT921X_ACL_TYPE_MISC); + entries[size].mask[1] =3D YT921X_ACL_BINb_MISC_L4_TYPE_M; + + return size + 1; +} + +static struct yt921x_acl_entry * +yt921x_acl_entries_find(struct yt921x_acl_entry *entries, unsigned int *si= zep, + u32 type) +{ + unsigned int size =3D *sizep; + + for (unsigned int i =3D 0; i < size; i++) + if (FIELD_GET(YT921X_ACL_KEYb_TYPE_M, entries[i].key[1]) =3D=3D + type) + return &entries[i]; + + if (size >=3D YT921X_ACL_ENT_PER_BLK) + return NULL; + + entries[size] =3D (typeof(*entries)){}; + entries[size].key[1] =3D YT921X_ACL_KEYb_TYPE(type); + + (*sizep)++; + return &entries[size]; +} + +static void +yt921x_acl_rule_set_ports(struct yt921x_acl_rule *aclrule, u16 ord, + u16 ports_mask) +{ + struct yt921x_acl_entry *entries =3D aclrule->entries; + + for (unsigned int i =3D 0; i < hweight8(aclrule->mask); i++) { + entries[i].key[1] |=3D YT921X_ACL_KEYb_SPORTS(ports_mask) | + YT921X_ACL_KEYb_ORD(ord); + } +} + +struct yt921x_acl_rule_ext { + struct yt921x_acl_rule r; + + struct yt921x_marker marker; +}; + +static int +yt921x_acl_rule_ext_parse_flow_entries(struct yt921x_acl_rule_ext *ruleext, + const struct flow_cls_offload *cls) +{ + const struct flow_rule *rule =3D flow_cls_offload_flow_rule(cls); + struct yt921x_acl_entry *entries =3D ruleext->r.entries; + struct netlink_ext_ack *extack =3D cls->common.extack; + const struct flow_dissector *dissector; + struct yt921x_acl_entry *entry; + unsigned int size =3D 0; + bool use_dport; + bool use_sport; + + /* Incomplete and probably won't, since it supports custom u32 filters. + * New adapters are welcome. + */ + dissector =3D rule->match.dissector; + if (dissector->used_keys & + ~(BIT_ULL(FLOW_DISSECTOR_KEY_CONTROL) | + BIT_ULL(FLOW_DISSECTOR_KEY_BASIC) | + BIT_ULL(FLOW_DISSECTOR_KEY_IPV4_ADDRS) | + BIT_ULL(FLOW_DISSECTOR_KEY_IPV6_ADDRS) | + BIT_ULL(FLOW_DISSECTOR_KEY_PORTS) | + BIT_ULL(FLOW_DISSECTOR_KEY_PORTS_RANGE) | + BIT_ULL(FLOW_DISSECTOR_KEY_ETH_ADDRS) | + BIT_ULL(FLOW_DISSECTOR_KEY_IP) | + BIT_ULL(FLOW_DISSECTOR_KEY_TCP))) { + NL_SET_ERR_MSG_MOD(extack, "Unsupported keys used"); + return -EOPNOTSUPP; + } + + /* Entries */ + if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_IPV4_ADDRS)) { + struct flow_match_ipv4_addrs match; + + flow_rule_match_ipv4_addrs(rule, &match); + + if (match.mask->dst) { + entry =3D yt921x_acl_entries_find(entries, &size, + YT921X_ACL_TYPE_IPV4_DA); + if (!entry) + goto err; + + entry->key[0] |=3D ntohl(match.key->dst); + entry->mask[0] |=3D ntohl(match.mask->dst); + } + + if (match.mask->src) { + entry =3D yt921x_acl_entries_find(entries, &size, + YT921X_ACL_TYPE_IPV4_SA); + if (!entry) + goto err; + + entry->key[0] |=3D ntohl(match.key->src); + entry->mask[0] |=3D ntohl(match.mask->src); + } + } + + if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_IPV6_ADDRS)) { + struct flow_match_ipv6_addrs match; + + flow_rule_match_ipv6_addrs(rule, &match); + + for (unsigned int i =3D 0; i < 4; i++) { + if (!match.mask->dst.s6_addr32[i]) + continue; + + entry =3D yt921x_acl_entries_find(entries, &size, + YT921X_ACL_TYPE_IPV6_DA0 + i); + if (!entry) + goto err; + + entry->key[0] |=3D ntohl(match.key->dst.s6_addr32[i]); + entry->mask[0] |=3D ntohl(match.mask->dst.s6_addr32[i]); + } + + for (unsigned int i =3D 0; i < 4; i++) { + if (!match.mask->src.s6_addr32[i]) + continue; + + entry =3D yt921x_acl_entries_find(entries, &size, + YT921X_ACL_TYPE_IPV6_SA0 + i); + if (!entry) + goto err; + + entry->key[0] |=3D ntohl(match.key->src.s6_addr32[i]); + entry->mask[0] |=3D ntohl(match.mask->src.s6_addr32[i]); + } + } + + use_dport =3D false; + use_sport =3D false; + if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_PORTS)) { + struct flow_match_ports match; + + entry =3D yt921x_acl_entries_find(entries, &size, + YT921X_ACL_TYPE_L4); + if (!entry) + goto err; + + flow_rule_match_ports(rule, &match); + + use_dport =3D !!match.mask->dst; + use_sport =3D !!match.mask->src; + + entry->key[0] |=3D (ntohs(match.key->dst) << 16) | + ntohs(match.key->src); + entry->mask[0] |=3D (ntohs(match.mask->dst) << 16) | + ntohs(match.mask->src); + } + + if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_PORTS_RANGE)) { + struct flow_match_ports_range match; + + entry =3D yt921x_acl_entries_find(entries, &size, + YT921X_ACL_TYPE_L4); + if (!entry) + goto err; + + flow_rule_match_ports_range(rule, &match); + + if ((use_dport && match.mask->tp.dst) || + (use_sport && match.mask->tp.src)) { + NL_SET_ERR_MSG_MOD(extack, + "Port mask and range are mutually exclusive"); + return -EINVAL; + } + + if (match.mask->tp.dst) { + entry->key[0] |=3D ntohs(match.key->tp_min.dst) << 16; + entry->key[1] |=3D YT921X_ACL_KEYb_L4_DPORT_RANGE_EN; + entry->mask[0] |=3D ntohs(match.key->tp_max.dst) << 16; + } + + if (match.mask->tp.src) { + entry->key[0] |=3D ntohs(match.key->tp_min.src); + entry->key[1] |=3D YT921X_ACL_KEYb_L4_SPORT_RANGE_EN; + entry->mask[0] |=3D ntohs(match.key->tp_max.src); + } + } + + if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_ETH_ADDRS)) { + struct flow_match_eth_addrs match; + u32 mask; + + flow_rule_match_eth_addrs(rule, &match); + + mask =3D ethaddr_hi4_to_u32(match.mask->dst); + if (mask) { + entry =3D yt921x_acl_entries_find(entries, &size, + YT921X_ACL_TYPE_MAC_DA0); + if (!entry) + goto err; + + entry->key[0] |=3D ethaddr_hi4_to_u32(match.key->dst); + entry->mask[0] |=3D mask; + } + + mask =3D ethaddr_hi4_to_u32(match.mask->src); + if (mask) { + entry =3D yt921x_acl_entries_find(entries, &size, + YT921X_ACL_TYPE_MAC_SA0); + if (!entry) + goto err; + + entry->key[0] |=3D ethaddr_hi4_to_u32(match.key->src); + entry->mask[0] |=3D mask; + } + + mask =3D (ethaddr_lo2_to_u32(match.mask->dst) << 16) | + ethaddr_lo2_to_u32(match.mask->src); + if (mask) { + entry =3D yt921x_acl_entries_find(entries, &size, + YT921X_ACL_TYPE_MAC_DA1_SA1); + if (!entry) + goto err; + + entry->key[0] |=3D (ethaddr_lo2_to_u32(match.key->dst) << 16) | + ethaddr_lo2_to_u32(match.key->src); + entry->mask[0] |=3D mask; + } + } + + /* Entries + Misc */ + if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_BASIC)) { + struct flow_match_basic match; + + flow_rule_match_basic(rule, &match); + + if (match.mask->n_proto) { + enum yt921x_l3_type type =3D YT921X_L3_TYPE_OTHER; + + if (match.mask->n_proto =3D=3D htons(~0)) + switch (match.key->n_proto) { + case htons(ETH_P_IP): + type =3D YT921X_L3_TYPE_IPV4; + break; + case htons(ETH_P_IPV6): + type =3D YT921X_L3_TYPE_IPV6; + break; + case htons(ETH_P_ARP): + type =3D YT921X_L3_TYPE_ARP; + break; + case htons(ETH_P_LLDP): + type =3D YT921X_L3_TYPE_LLDP; + break; + case htons(ETH_P_PAE): + type =3D YT921X_L3_TYPE_PAE; + break; + case htons(ETH_P_CFM): + type =3D YT921X_L3_TYPE_ERP; + break; + } + + if (type !=3D YT921X_L3_TYPE_OTHER) { + size =3D yt921x_acl_entries_set_l3_type(entries, + size, + type); + if (!size) + goto err; + } else { + entry =3D yt921x_acl_entries_find(entries, &size, + YT921X_ACL_TYPE_ETHERTYPE); + if (!entry) + goto err; + + entry->key[0] |=3D ntohs(match.key->n_proto); + entry->mask[0] |=3D ntohs(match.mask->n_proto); + } + } + + if (match.mask->ip_proto) { + enum yt921x_l4_type type =3D YT921X_L4_TYPE_OTHER; + + if (match.mask->ip_proto =3D=3D (u8)~0) + switch (match.key->ip_proto) { + case IPPROTO_TCP: + type =3D YT921X_L4_TYPE_TCP; + break; + case IPPROTO_UDP: + type =3D YT921X_L4_TYPE_UDP; + break; + case IPPROTO_UDPLITE: + type =3D YT921X_L4_TYPE_UDPLITE; + break; + case IPPROTO_ICMP: + type =3D YT921X_L4_TYPE_ICMP; + break; + case IPPROTO_IGMP: + type =3D YT921X_L4_TYPE_IGMP; + break; + } + + if (type !=3D YT921X_L4_TYPE_OTHER) { + size =3D yt921x_acl_entries_set_l4_type(entries, + size, + type); + if (!size) + goto err; + } else { + entry =3D yt921x_acl_entries_find(entries, &size, + YT921X_ACL_TYPE_MISC); + if (!entry) + goto err; + + entry->key[0] |=3D YT921X_ACL_BINa_MISC_IP_PROTO(match.key->ip_proto); + entry->mask[0] |=3D YT921X_ACL_BINa_MISC_IP_PROTO(match.mask->ip_proto= ); + } + } + } + + if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_CONTROL)) { + u32 supp_flags =3D FLOW_DIS_IS_FRAGMENT | FLOW_DIS_FIRST_FRAG; + struct flow_match_control match; + + flow_rule_match_control(rule, &match); + if (!flow_rule_is_supp_control_flags(supp_flags, + match.mask->flags, extack)) + return -EOPNOTSUPP; + + if (match.mask->flags & FLOW_DIS_FIRST_FRAG) { + bool set =3D match.key->flags & FLOW_DIS_FIRST_FRAG; + + size =3D yt921x_acl_entries_set_first_frag(entries, size, + set); + if (!size) + goto err; + } + if (match.mask->flags & FLOW_DIS_IS_FRAGMENT) { + bool set =3D match.key->flags & FLOW_DIS_IS_FRAGMENT; + + size =3D yt921x_acl_entries_set_is_fragment(entries, size, + set); + if (!size) + goto err; + } + } + + /* Misc only */ + if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_IP)) { + struct flow_match_ip match; + + flow_rule_match_ip(rule, &match); + if (match.mask->ttl) { + NL_SET_ERR_MSG_MOD(extack, + "Matching on TTL not supported"); + return -EOPNOTSUPP; + } + + if (match.mask->tos) { + entry =3D yt921x_acl_entries_find(entries, &size, + YT921X_ACL_TYPE_MISC); + if (!entry) + goto err; + + entry->key[0] |=3D YT921X_ACL_BINa_MISC_TOS(match.key->tos); + entry->mask[0] |=3D YT921X_ACL_BINa_MISC_TOS(match.mask->tos); + } + } + + if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_TCP)) { + struct flow_match_tcp match; + + flow_rule_match_tcp(rule, &match); + + if (match.mask->flags) { + entry =3D yt921x_acl_entries_find(entries, &size, + YT921X_ACL_TYPE_MISC); + if (!entry) + goto err; + + entry->key[0] |=3D YT921X_ACL_BINa_MISC_TCP_FLAGS(ntohs(match.key->flag= s)); + entry->mask[0] |=3D YT921X_ACL_BINa_MISC_TCP_FLAGS(ntohs(match.mask->fl= ags)); + } + } + + if (!size) { + NL_SET_ERR_MSG_MOD(extack, "Empty rule generated, this should not happen= "); + return -EOPNOTSUPP; + } + + ruleext->r.mask =3D (1 << size) - 1; + return 0; + +err: + NL_SET_ERR_MSG_MOD(extack, "Rule too complex"); + return -EOPNOTSUPP; +} + +static int +yt921x_acl_rule_ext_parse_flow_action(struct yt921x_acl_rule_ext *ruleext, + const struct flow_action *flow_action, + struct netlink_ext_ack *extack, + struct yt921x_priv *priv, int port) +{ + enum flow_action_id redir_act =3D NUM_FLOW_ACTIONS; + const struct flow_action_entry *act; + u32 *action =3D ruleext->r.action; + unsigned int i; + int res; + + memset(action, 0, 3 * sizeof(*action)); + flow_action_for_each(i, act, flow_action) + switch (act->id) { + case FLOW_ACTION_ACCEPT: + case FLOW_ACTION_DROP: + case FLOW_ACTION_TRAP: + case FLOW_ACTION_REDIRECT: + if (redir_act !=3D NUM_FLOW_ACTIONS && + redir_act !=3D act->id) { + NL_SET_ERR_MSG_MOD(extack, + "Multiple redirect actions"); + return -EOPNOTSUPP; + } + redir_act =3D act->id; + + switch (act->id) { + case FLOW_ACTION_ACCEPT: + action[2] |=3D YT921X_ACL_ACTc_FWD_EN | + YT921X_ACL_ACTc_FWD_FWD; + break; + case FLOW_ACTION_DROP: + action[2] |=3D YT921X_ACL_ACTc_FWD_EN | + YT921X_ACL_ACTc_FWD_REDIR; + break; + case FLOW_ACTION_TRAP: + action[2] |=3D YT921X_ACL_ACTc_FWD_EN | + YT921X_ACL_ACTc_FWD_TRAP; + break; + case FLOW_ACTION_REDIRECT: { + struct dsa_port *to_dp; + + to_dp =3D dsa_port_from_netdev(act->dev); + if (IS_ERR(to_dp) || to_dp->ds !=3D &priv->ds) { + NL_SET_ERR_MSG_MOD(extack, + "Destination not on this switch HW"); + return -EOPNOTSUPP; + } + + action[2] |=3D YT921X_ACL_ACTc_FWD_EN | + YT921X_ACL_ACTc_FWD_REDIR | + YT921X_ACL_ACTc_FWD_REDIR_DPORTn(to_dp->index); + break; + } + default: + break; + } + break; + case FLOW_ACTION_PRIORITY: + if (act->priority >=3D YT921X_PRIO_NUM) { + NL_SET_ERR_MSG_MOD(extack, + "Priority value is too high"); + return -EOPNOTSUPP; + } + action[0] |=3D YT921X_ACL_ACTa_PRIO_EN; + action[1] |=3D YT921X_ACL_ACTb_PRIO(act->priority); + break; + case FLOW_ACTION_POLICE: { + const struct flow_action_police *police =3D &act->police; + + res =3D yt921x_police_validate(police, flow_action, act, + extack); + if (res) + return res; + + res =3D yt921x_marker_tfm_police(&ruleext->marker, police, + 0, priv, port, extack); + if (res) + return res; + + action[0] |=3D YT921X_ACL_ACTa_METER_EN; + break; + } + default: + NL_SET_ERR_MSG_MOD(extack, "Action not supported"); + return -EOPNOTSUPP; + } + + return 0; +} + +static int +yt921x_acl_rule_ext_parse_flow(struct yt921x_acl_rule_ext *ruleext, int po= rt, + const struct flow_cls_offload *cls, bool ingress, + struct yt921x_priv *priv) +{ + const struct flow_rule *rule =3D flow_cls_offload_flow_rule(cls); + struct netlink_ext_ack *extack =3D cls->common.extack; + int res; + + if (!ingress) { + NL_SET_ERR_MSG_MOD(extack, "Only ingress is supported"); + return -EOPNOTSUPP; + } + + if (cls->common.chain_index) { + NL_SET_ERR_MSG(extack, "Only chain 0 is supported"); + return -EOPNOTSUPP; + } + + res =3D yt921x_acl_rule_ext_parse_flow_action(ruleext, &rule->action, + extack, priv, port); + if (res) + return res; + res =3D yt921x_acl_rule_ext_parse_flow_entries(ruleext, cls); + if (res) + return res; + + yt921x_acl_rule_set_ports(&ruleext->r, 0, BIT(port)); + ruleext->r.tag =3D cls->cookie; + ruleext->r.type =3D TC_SETUP_CLSFLOWER; + return 0; +} + +static unsigned int +yt921x_acl_find(const struct yt921x_priv *priv, enum tc_setup_type type, + unsigned long tag) +{ + for (unsigned int blkid =3D 0; blkid < YT921X_ACL_BLK_NUM; blkid++) { + const struct yt921x_acl_blk *aclblk =3D priv->acl_blks[blkid]; + + if (!aclblk) + continue; + + for (unsigned int i =3D 0; i < YT921X_ACL_ENT_PER_BLK; i++) + if (aclblk->rules[i] && aclblk->rules[i]->tag =3D=3D tag && + aclblk->rules[i]->type =3D=3D type) + return YT921X_ACL_ENT_PER_BLK * blkid + i; + } + + return UINT_MAX; +} + +static unsigned int +yt921x_acl_reserve(struct yt921x_priv *priv, unsigned int entscnt, + struct netlink_ext_ack *extack) +{ + int candidates[YT921X_ACL_ENT_PER_BLK + 1]; + unsigned int acl_used_cnt =3D 0; + + if (WARN_ON(entscnt > YT921X_ACL_ENT_PER_BLK)) + return UINT_MAX; + + for (unsigned int i =3D 0; i < ARRAY_SIZE(candidates); i++) + candidates[i] =3D -1; + for (unsigned int i =3D 0; i < YT921X_ACL_BLK_NUM; i++) { + unsigned int blk_used_cnt =3D hweight8(priv->acl_masks[i]); + + candidates[blk_used_cnt] =3D i; + acl_used_cnt +=3D blk_used_cnt; + } + + if (acl_used_cnt >=3D YT921X_ACL_NUM) { + NL_SET_ERR_MSG_MOD(extack, "ACL entry limit reached"); + return UINT_MAX; + } + if (acl_used_cnt + entscnt <=3D YT921X_ACL_NUM) + for (unsigned int i =3D YT921X_ACL_ENT_PER_BLK - entscnt + 1; + i-- > 0;) + if (candidates[i] >=3D 0) + return YT921X_ACL_ENT_PER_BLK * candidates[i] + + ffz(priv->acl_masks[candidates[i]]); + + NL_SET_ERR_MSG_MOD(extack, + "ACL entry allocation failed, simplify your rules or remove existing= rules"); + return UINT_MAX; +} + +static int +yt921x_acl_commit(struct yt921x_priv *priv, unsigned int entid, u8 entsmas= k) +{ + const struct yt921x_acl_rule *aclrule; + const struct yt921x_acl_blk *aclblk; + unsigned int blkid; + unsigned int binid; + unsigned long mask; + u32 zeros[3] =3D {}; + unsigned int i; + unsigned int o; + u32 ctrl; + int res; + + blkid =3D entid / YT921X_ACL_ENT_PER_BLK; + binid =3D entid % YT921X_ACL_ENT_PER_BLK; + aclblk =3D priv->acl_blks[blkid]; + aclrule =3D aclblk->rules[binid]; + + /* Write actions */ + res =3D yt921x_reg96_write(priv, YT921X_ACLn_ACT(entid), + aclrule ? aclrule->action : zeros); + if (res) + return res; + + /* Open the block */ + ctrl =3D YT921X_ACL_BLK_CMD_MODIFY | YT921X_ACL_BLK_CMD_BLKID(blkid); + res =3D yt921x_reg_write(priv, YT921X_ACL_BLK_CMD, ctrl); + if (res) + return res; + + /* Write keys and masks */ + ctrl =3D 0; + for (unsigned int i =3D 0; i < YT921X_ACL_ENT_PER_BLK; i++) + ctrl |=3D YT921X_ACL_BLK_KEEP_KEEPn(i); + + mask =3D entsmask; + i =3D 0; + for_each_set_bit(o, &mask, YT921X_ACL_ENT_PER_BLK) { + res =3D yt921x_reg64_write(priv, YT921X_ACLn_KEYm(blkid, o), + aclrule ? aclrule->entries[i].key : + zeros); + if (res) + return res; + + res =3D yt921x_reg64_write(priv, YT921X_ACLn_MASKm(blkid, o), + aclrule ? aclrule->entries[i].mask : + zeros); + if (res) + return res; + + ctrl &=3D ~YT921X_ACL_BLK_KEEP_KEEPn(o); + i++; + } + + res =3D yt921x_reg_write(priv, YT921X_ACL_BLK_KEEP, ctrl); + if (res) + return res; + + ctrl =3D 0; + for (unsigned int i =3D 0; i < YT921X_ACL_ENT_PER_BLK; i++) { + const struct yt921x_acl_rule *other =3D aclblk->rules[i]; + + if (!other) + continue; + + mask =3D other->mask; + for_each_set_bit(o, &mask, YT921X_ACL_ENT_PER_BLK) + ctrl |=3D YT921X_ACL_ENTRY_ENm(o) | + YT921X_ACL_ENTRY_GRPIDm(o, i); + } + res =3D yt921x_reg_write(priv, YT921X_ACLn_ENTRY(blkid), ctrl); + if (res) + return res; + + /* Close the block */ + ctrl =3D YT921X_ACL_BLK_CMD_BLKID(blkid); + res =3D yt921x_reg_write(priv, YT921X_ACL_BLK_CMD, ctrl); + if (res) + return res; + + return 0; +} + +static int +yt921x_acl_del(struct yt921x_priv *priv, enum tc_setup_type type, + unsigned long tag) +{ + struct device *dev =3D to_device(priv); + struct yt921x_acl_rule *aclrule; + struct yt921x_acl_blk *aclblk; + unsigned int binid; + unsigned int blkid; + unsigned int entid; + int res; + + entid =3D yt921x_acl_find(priv, type, tag); + if (entid =3D=3D UINT_MAX) + return -ENOENT; + + blkid =3D entid / YT921X_ACL_ENT_PER_BLK; + binid =3D entid % YT921X_ACL_ENT_PER_BLK; + aclblk =3D priv->acl_blks[blkid]; + aclrule =3D aclblk->rules[binid]; + + aclblk->rules[binid] =3D NULL; + res =3D yt921x_acl_commit(priv, entid, aclrule->mask); + if (res) { + aclblk->rules[binid] =3D aclrule; + return res; + } + + if (aclrule->action[0] & YT921X_ACL_ACTa_METER_EN) + clear_bit(FIELD_GET(YT921X_ACL_ACTa_METER_ID_M, + aclrule->action[0]), + priv->meters_map); + priv->acl_masks[blkid] &=3D ~aclrule->mask; + devm_kfree(dev, aclrule); + if (!priv->acl_masks[blkid]) { + devm_kfree(dev, aclblk); + priv->acl_blks[blkid] =3D NULL; + } + return 0; +} + +static int +yt921x_acl_add(struct yt921x_priv *priv, + const struct yt921x_acl_rule_ext *ruleext, + struct netlink_ext_ack *extack) +{ + bool use_meter =3D ruleext->r.action[0] & YT921X_ACL_ACTa_METER_EN; + unsigned int entscnt =3D hweight8(ruleext->r.mask); + struct device *dev =3D to_device(priv); + struct yt921x_acl_rule *aclrule; + struct yt921x_acl_blk *aclblk; + unsigned int meterid; + unsigned long mask; + unsigned int binid; + unsigned int blkid; + unsigned int entid; + unsigned int o; + int res; + + /* Allocate resources */ + entid =3D yt921x_acl_reserve(priv, entscnt, extack); + if (entid =3D=3D UINT_MAX) + return -EOPNOTSUPP; + + if (use_meter) { + meterid =3D find_first_zero_bit(priv->meters_map, + YT921X_METER_NUM); + if (meterid >=3D YT921X_METER_NUM) { + NL_SET_ERR_MSG_MOD(extack, + "No more meters available"); + return -EOPNOTSUPP; + } + + res =3D yt921x_meter_config(priv, meterid, &ruleext->marker); + if (res) + return res; + } + + /* Prepare acl block ctrlblk */ + blkid =3D entid / YT921X_ACL_ENT_PER_BLK; + binid =3D entid % YT921X_ACL_ENT_PER_BLK; + aclblk =3D priv->acl_blks[blkid]; + if (!aclblk) { + aclblk =3D devm_kzalloc(dev, sizeof(*aclblk), GFP_KERNEL); + if (!aclblk) + return -ENOMEM; + priv->acl_blks[blkid] =3D aclblk; + } + + /* Prepare acl rule ctrlblk */ + aclrule =3D devm_kmemdup(dev, &ruleext->r, + offsetof(struct yt921x_acl_rule, + entries[entscnt]), + GFP_KERNEL); + if (!aclrule) { + res =3D -ENOMEM; + goto err; + } + + /* Replace the placeholder resource IDs */ + aclrule->mask =3D 0; + mask =3D priv->acl_masks[blkid]; + for_each_clear_bit(o, &mask, YT921X_ACL_ENT_PER_BLK) { + aclrule->mask |=3D BIT(o); + entscnt--; + if (!entscnt) + break; + } + + if (use_meter) + aclrule->action[0] |=3D YT921X_ACL_ACTa_METER_ID(meterid); + + /* Write rules */ + aclblk->rules[binid] =3D aclrule; + res =3D yt921x_acl_commit(priv, entid, aclrule->mask); + if (res) { + aclblk->rules[binid] =3D NULL; + devm_kfree(dev, aclrule); + goto err; + } + + if (use_meter) + set_bit(meterid, priv->meters_map); + priv->acl_masks[blkid] |=3D aclrule->mask; + return 0; + +err: + if (!priv->acl_masks[blkid]) { + devm_kfree(dev, aclblk); + priv->acl_blks[blkid] =3D NULL; + } + return res; +} + +static int +yt921x_dsa_cls_flower_del(struct dsa_switch *ds, int port, + struct flow_cls_offload *cls, bool ingress) +{ + struct yt921x_priv *priv =3D to_yt921x_priv(ds); + int res; + + mutex_lock(&priv->reg_lock); + res =3D yt921x_acl_del(priv, TC_SETUP_CLSFLOWER, cls->cookie); + mutex_unlock(&priv->reg_lock); + + return res; +} + +static int +yt921x_dsa_cls_flower_add(struct dsa_switch *ds, int port, + struct flow_cls_offload *cls, bool ingress) +{ + struct netlink_ext_ack *extack =3D cls->common.extack; + struct yt921x_priv *priv =3D to_yt921x_priv(ds); + struct yt921x_acl_rule_ext ruleext; + int res; + + res =3D yt921x_acl_rule_ext_parse_flow(&ruleext, port, cls, ingress, + priv); + if (res) + return res; + + mutex_lock(&priv->reg_lock); + res =3D yt921x_acl_add(priv, &ruleext, extack); + mutex_unlock(&priv->reg_lock); + + return res; +} + static int yt921x_mirror_del(struct yt921x_priv *priv, int port, bool ingress) { @@ -1747,12 +2729,12 @@ yt921x_fdb_in01(struct yt921x_priv *priv, const uns= igned char *addr, u32 ctrl; int res; =20 - ctrl =3D (addr[0] << 24) | (addr[1] << 16) | (addr[2] << 8) | addr[3]; + ctrl =3D ethaddr_hi4_to_u32(addr); res =3D yt921x_reg_write(priv, YT921X_FDB_IN0, ctrl); if (res) return res; =20 - ctrl =3D ctrl1 | YT921X_FDB_IO1_FID(vid) | (addr[4] << 8) | addr[5]; + ctrl =3D ctrl1 | YT921X_FDB_IO1_FID(vid) | ethaddr_lo2_to_u32(addr); return yt921x_reg_write(priv, YT921X_FDB_IN1, ctrl); } =20 @@ -3613,6 +4595,24 @@ static int yt921x_chip_setup_tc(struct yt921x_priv *= priv) return 0; } =20 +static int yt921x_chip_setup_acl(struct yt921x_priv *priv) +{ + u32 ctrl; + int res; + + ctrl =3D YT921X_ACL_PERMIT_UNMATCH_PORTS_M; + res =3D yt921x_reg_write(priv, YT921X_ACL_PERMIT_UNMATCH, ctrl); + if (res) + return res; + + ctrl =3D YT921X_ACL_PORT_PORTS_M; + res =3D yt921x_reg_write(priv, YT921X_ACL_PORT, ctrl); + if (res) + return res; + + return 0; +} + static int __maybe_unused yt921x_chip_setup_qos(struct yt921x_priv *priv) { u32 ctrl; @@ -3659,7 +4659,7 @@ static int yt921x_chip_setup(struct yt921x_priv *priv) u32 ctrl; int res; =20 - ctrl =3D YT921X_FUNC_MIB | YT921X_FUNC_METER; + ctrl =3D YT921X_FUNC_MIB | YT921X_FUNC_ACL | YT921X_FUNC_METER; res =3D yt921x_reg_set_bits(priv, YT921X_FUNC, ctrl); if (res) return res; @@ -3672,6 +4672,10 @@ static int yt921x_chip_setup(struct yt921x_priv *pri= v) if (res) return res; =20 + res =3D yt921x_chip_setup_acl(priv); + if (res) + return res; + #if IS_ENABLED(CONFIG_DCB) res =3D yt921x_chip_setup_qos(priv); if (res) @@ -3767,6 +4771,9 @@ static const struct dsa_switch_ops yt921x_dsa_switch_= ops =3D { .port_policer_del =3D yt921x_dsa_port_policer_del, .port_policer_add =3D yt921x_dsa_port_policer_add, .port_setup_tc =3D yt921x_dsa_port_setup_tc, + /* acl */ + .cls_flower_del =3D yt921x_dsa_cls_flower_del, + .cls_flower_add =3D yt921x_dsa_cls_flower_add, /* hsr */ .port_hsr_leave =3D dsa_port_simple_hsr_leave, .port_hsr_join =3D dsa_port_simple_hsr_join, diff --git a/drivers/net/dsa/yt921x.h b/drivers/net/dsa/yt921x.h index 70fa780c337f..341b607fa89a 100644 --- a/drivers/net/dsa/yt921x.h +++ b/drivers/net/dsa/yt921x.h @@ -24,6 +24,7 @@ #define YT921X_RST_SW BIT(1) #define YT921X_FUNC 0x80004 #define YT921X_FUNC_METER BIT(4) +#define YT921X_FUNC_ACL BIT(2) #define YT921X_FUNC_MIB BIT(1) #define YT921X_CHIP_ID 0x80008 #define YT921X_CHIP_ID_MAJOR GENMASK(31, 16) @@ -420,6 +421,10 @@ enum yt921x_app_selector { #define YT921X_CPU_COPY_FORCE_INT_PORT BIT(2) #define YT921X_CPU_COPY_TO_INT_CPU BIT(1) #define YT921X_CPU_COPY_TO_EXT_CPU BIT(0) +#define YT921X_ACL_PERMIT_UNMATCH 0x1806a0 +#define YT921X_ACL_PERMIT_UNMATCH_PORTS_M GENMASK(10, 0) +#define YT921X_ACL_PERMIT_UNMATCH_PORTS(x) FIELD_PREP(YT921X_ACL_PERMIT= _UNMATCH_PORTS_M, (x)) +#define YT921X_ACL_PERMIT_UNMATCH_PORTn(port) BIT(port) #define YT921X_ACT_UNK_UCAST 0x180734 #define YT921X_ACT_UNK_MCAST 0x180738 #define YT921X_ACT_UNK_MCAST_BYPASS_DROP_RMA BIT(23) @@ -454,6 +459,249 @@ enum yt921x_app_selector { #define YT921X_VLAN_CTRLa_METER_EN BIT(5) #define YT921X_VLAN_CTRLa_METER_ID_M GENMASK(4, 0) =20 +#define YT921X_ACLn_ACT(n) (0x1c0000 + 0x10 * (n)) +#define YT921X_ACL_ACTc_STAG_M GENMASK(26, 25) +#define YT921X_ACL_ACTc_STAG(x) FIELD_PREP(YT921X_ACL_ACTc_STAG_M, (x)) +#define YT921X_ACL_ACTc_STAG_DONTCARE YT921X_ACL_ACTc_STAG(0) +#define YT921X_ACL_ACTc_STAG_UNTAG YT921X_ACL_ACTc_STAG(1) +#define YT921X_ACL_ACTc_STAG_TAG YT921X_ACL_ACTc_STAG(2) +#define YT921X_ACL_ACTc_STAG_KEEP YT921X_ACL_ACTc_STAG(3) +#define YT921X_ACL_ACTc_CTAG_M GENMASK(24, 23) +#define YT921X_ACL_ACTc_CTAG(x) FIELD_PREP(YT921X_ACL_ACTc_CTAG_M, (x)) +#define YT921X_ACL_ACTc_CTAG_DONTCARE YT921X_ACL_ACTc_CTAG(0) +#define YT921X_ACL_ACTc_CTAG_UNTAG YT921X_ACL_ACTc_CTAG(1) +#define YT921X_ACL_ACTc_CTAG_TAG YT921X_ACL_ACTc_CTAG(2) +#define YT921X_ACL_ACTc_CTAG_KEEP YT921X_ACL_ACTc_CTAG(3) +#define YT921X_ACL_ACTc_FWD_M GENMASK(22, 21) +#define YT921X_ACL_ACTc_FWD(x) FIELD_PREP(YT921X_ACL_ACTc_FWD_M, (x)) +#define YT921X_ACL_ACTc_FWD_FWD YT921X_ACL_ACTc_FWD(0) +#define YT921X_ACL_ACTc_FWD_COPY YT921X_ACL_ACTc_FWD(1) +#define YT921X_ACL_ACTc_FWD_REDIR YT921X_ACL_ACTc_FWD(2) +#define YT921X_ACL_ACTc_FWD_TRAP YT921X_ACL_ACTc_FWD(3) +#define YT921X_ACL_ACTc_FWD_REDIR_DPORTS_M GENMASK(20, 10) +#define YT921X_ACL_ACTc_FWD_REDIR_DPORTS(x) FIELD_PREP(YT921X_ACL_ACTc_= FWD_REDIR_DPORTS_M, (x)) +#define YT921X_ACL_ACTc_FWD_REDIR_DPORTn(port) BIT((port) + 10) +#define YT921X_ACL_ACTc_FWD_EN BIT(9) +#define YT921X_ACL_ACTc_SDEI BIT(8) +#define YT921X_ACL_ACTc_SDEI_REPLACE BIT(7) +#define YT921X_ACL_ACTc_SPRI_M GENMASK(6, 4) +#define YT921X_ACL_ACTc_SPRI(x) FIELD_PREP(YT921X_ACL_ACTc_SPRI_M, (x)) +#define YT921X_ACL_ACTc_SPRI_REPLACE BIT(3) +#define YT921X_ACL_ACTbc_SVID_M GENMASK_ULL(34, 23) +#define YT921X_ACL_ACTbc_SVID(x) FIELD_PREP(YT921X_ACL_ACTbc_SVID_M, (= x)) +#define YT921X_ACL_ACTb_SVID_REPLACE BIT(22) +#define YT921X_ACL_ACTb_CDEI BIT(21) +#define YT921X_ACL_ACTb_CDEI_REPLACE BIT(20) +#define YT921X_ACL_ACTb_CPRI_M GENMASK(19, 17) +#define YT921X_ACL_ACTb_CPRI(x) FIELD_PREP(YT921X_ACL_ACTb_CPRI_M, (x)) +#define YT921X_ACL_ACTb_CPRI_REPLACE BIT(16) +#define YT921X_ACL_ACTb_CVID_M GENMASK(15, 4) +#define YT921X_ACL_ACTb_CVID(x) FIELD_PREP(YT921X_ACL_ACTb_CVID_M, (x)) +#define YT921X_ACL_ACTb_CVID_REPLACE BIT(3) +#define YT921X_ACL_ACTb_PRIO_M GENMASK(2, 0) +#define YT921X_ACL_ACTb_PRIO(x) FIELD_PREP(YT921X_ACL_ACTb_PRIO_M, (x)) +#define YT921X_ACL_ACTa_PRIO_EN BIT(31) +#define YT921X_ACL_ACTa_COLOR_M GENMASK(30, 29) +#define YT921X_ACL_ACTa_COLOR(x) FIELD_PREP(YT921X_ACL_ACTa_COLOR_M, (= x)) +#define YT921X_ACL_ACTa_COLOR_GREEN YT921X_ACL_ACTa_COLOR(0) +#define YT921X_ACL_ACTa_COLOR_YELLOW YT921X_ACL_ACTa_COLOR(1) +#define YT921X_ACL_ACTa_COLOR_RED YT921X_ACL_ACTa_COLOR(2) +#define YT921X_ACL_ACTa_COLOR_EN BIT(28) +#define YT921X_ACL_ACTa_DSCP_M GENMASK(27, 22) +#define YT921X_ACL_ACTa_DSCP(x) FIELD_PREP(YT921X_ACL_ACTa_DSCP_M, (x)) +#define YT921X_ACL_ACTa_DSCP_REPLACE BIT(21) +#define YT921X_ACL_ACTa_METER_ID_M GENMASK(20, 15) +#define YT921X_ACL_ACTa_METER_ID(x) FIELD_PREP(YT921X_ACL_ACTa_METER_I= D_M, (x)) +#define YT921X_ACL_ACTa_METER_EN BIT(14) +#define YT921X_ACL_ACTa_MIRROR_EN BIT(13) +#define YT921X_ACL_ACTa_FLOWSTAT_EN BIT(12) +#define YT921X_ACL_ACTa_FLOWSTAT_ID_M GENMASK(11, 6) +#define YT921X_ACL_ACTa_FLOWSTAT_ID(x) FIELD_PREP(YT921X_ACL_ACTa_FLOWS= TAT_ID_M, (x)) +#define YT921X_ACL_ACTa_GPIO_EN BIT(5) +#define YT921X_ACL_ACTa_GPIO_PIN_M GENMASK(4, 1) +#define YT921X_ACL_ACTa_GPIO_PIN(x) FIELD_PREP(YT921X_ACL_ACTa_GPIO_PI= N_M, (x)) +#define YT921X_ACL_ACTa_INTR_EN BIT(0) +#define YT921X_ACL_BLK_KEEP 0x201000 +#define YT921X_ACL_BLK_KEEP_GRPIDn_M(bin) (7 << (4 * (bin) + 1)) +#define YT921X_ACL_BLK_KEEP_GRPIDn(bin, x) ((x) << (4 * (bin) + 1)) +#define YT921X_ACL_BLK_KEEP_KEEPn(bin) BIT(4 * (bin)) +#define YT921X_ACL_PORT 0x202000 +#define YT921X_ACL_PORT_PORTS_M GENMASK(10, 0) +#define YT921X_ACL_PORT_PORTS(x) FIELD_PREP(YT921X_ACL_PORT_PORTS_M, (= x)) +#define YT921X_ACL_PORT_PORTn(port) BIT(port) +#define YT921X_ACL_BLK_CMD 0x202004 +#define YT921X_ACL_BLK_CMD_BLKID_M GENMASK(6, 1) +#define YT921X_ACL_BLK_CMD_BLKID(x) FIELD_PREP(YT921X_ACL_BLK_CMD_BLKI= D_M, (x)) +#define YT921X_ACL_BLK_CMD_MODIFY BIT(0) +#define YT921X_ACLn_ENTRY(blk) (0x203000 + 4 * (blk)) +#define YT921X_ACL_ENTRY_GRPIDm_M(bin) (7 << (4 * (bin) + 1)) +#define YT921X_ACL_ENTRY_GRPIDm(bin, x) ((x) << (4 * (bin) + 1)) +#define YT921X_ACL_ENTRY_ENm(bin) BIT(4 * (bin)) +#define YT921X_ACLn_KEYm(blk, bin) (0x204000 + 0x200 * (bin) + 8 * (blk)) +#define YT921X_ACL_KEYb_ORD_M GENMASK(29, 21) +#define YT921X_ACL_KEYb_ORD(x) FIELD_PREP(YT921X_ACL_KEYb_ORD_M, (x)) +#define YT921X_ACL_KEYb_SPORTS_M GENMASK(20, 10) +#define YT921X_ACL_KEYb_SPORTS(x) FIELD_PREP(YT921X_ACL_KEYb_SPORTS_M,= (x)) +#define YT921X_ACL_KEYb_SPORTn(port) BIT((port) + 10) +#define YT921X_ACL_KEYb_REVERSE BIT(9) /* reverse match */ +#define YT921X_ACL_KEYb_TYPE_M GENMASK(8, 4) +#define YT921X_ACL_KEYb_TYPE(x) FIELD_PREP(YT921X_ACL_KEYb_TYPE_M, (x)) +/* KEY_* fields need no masks */ +#define YT921X_ACLn_MASKm(blk, bin) (0x205000 + 0x200 * (bin) + 8 * (blk)) + +enum yt921x_acl_type { + YT921X_ACL_TYPE_NA, + YT921X_ACL_TYPE_MAC_DA0, + YT921X_ACL_TYPE_MAC_SA0, + YT921X_ACL_TYPE_MAC_DA1_SA1, + YT921X_ACL_TYPE_VLAN, + YT921X_ACL_TYPE_VTAG, + YT921X_ACL_TYPE_IPV4_DA, + YT921X_ACL_TYPE_IPV4_SA, + YT921X_ACL_TYPE_IPV6_DA0, + YT921X_ACL_TYPE_IPV6_DA1, + YT921X_ACL_TYPE_IPV6_DA2, + YT921X_ACL_TYPE_IPV6_DA3, + YT921X_ACL_TYPE_IPV6_SA0, + YT921X_ACL_TYPE_IPV6_SA1, + YT921X_ACL_TYPE_IPV6_SA2, + YT921X_ACL_TYPE_IPV6_SA3, + YT921X_ACL_TYPE_MISC, + YT921X_ACL_TYPE_L4, + YT921X_ACL_TYPE_UDF0, + YT921X_ACL_TYPE_UDF1, + YT921X_ACL_TYPE_UDF2, + YT921X_ACL_TYPE_UDF3, + YT921X_ACL_TYPE_UDF4, + YT921X_ACL_TYPE_UDF5, + YT921X_ACL_TYPE_UDF6, + YT921X_ACL_TYPE_UDF7, + YT921X_ACL_TYPE_ETHERTYPE, + YT921X_ACL_TYPE_NUM +}; + +/* Range: turn KEY:MASK into MIN:MAX */ + +#define YT921X_ACL_BINb_MAC_xA0_L3_TYPE_M GENMASK(3, 0) +#define YT921X_ACL_BINb_MAC_xA0_L3_TYPE(x) FIELD_PREP(YT921X_ACL_BINb_M= AC_xA0_L3_TYPE_M, (x)) +#define YT921X_ACL_BINa_MAC_xA0_MAC_xA0_M GENMASK(31, 0) + +#define YT921X_ACL_BINb_MAC_DA1_SA1_L2_TYPE_M GENMASK(2, 0) +#define YT921X_ACL_BINb_MAC_DA1_SA1_L2_TYPE(x) FIELD_PREP(YT921X_ACL_BIN= b_MAC_DA1_SA1_L2_TYPE_M, (x)) +#define YT921X_ACL_BINa_MAC_DA1_SA1_MAC_DA1_M GENMASK(31, 16) +#define YT921X_ACL_BINa_MAC_DA1_SA1_MAC_SA1_M GENMASK(15, 0) + +#define YT921X_ACL_KEYb_VLAN_SVID_RANGE_EN BIT(31) +#define YT921X_ACL_KEYb_VLAN_CVID_RANGE_EN BIT(30) +#define YT921X_ACL_BINb_VLAN_CDEI BIT(3) +#define YT921X_ACL_BINb_VLAN_CPRI_M GENMASK(2, 0) +#define YT921X_ACL_BINb_VLAN_CPRI(x) FIELD_PREP(YT921X_ACL_BINb_VLAN_C= PRI_M, (x)) +#define YT921X_ACL_BINa_VLAN_CTAG_FMT_M GENMASK(31, 30) +#define YT921X_ACL_BINa_VLAN_CTAG_FMT(x) FIELD_PREP(YT921X_ACL_BINa_VLA= N_CTAG_FMT_M, (x)) +#define YT921X_ACL_BINa_VLAN_SDEI BIT(29) +#define YT921X_ACL_BINa_VLAN_SPRI_M GENMASK(28, 26) +#define YT921X_ACL_BINa_VLAN_SPRI(x) FIELD_PREP(YT921X_ACL_BINa_VLAN_S= PRI_M, (x)) +#define YT921X_ACL_BINa_VLAN_STAG_FMT_M GENMASK(25, 24) +#define YT921X_ACL_BINa_VLAN_STAG_FMT(x) FIELD_PREP(YT921X_ACL_BINa_VLA= N_STAG_FMT_M, (x)) +#define YT921X_ACL_BINa_VLAN_SVID_M GENMASK(23, 12) +#define YT921X_ACL_BINa_VLAN_SVID(x) FIELD_PREP(YT921X_ACL_BINa_VLAN_S= VID_M, (x)) +#define YT921X_ACL_BINa_VLAN_CVID_M GENMASK(11, 0) +#define YT921X_ACL_BINa_VLAN_CVID(x) FIELD_PREP(YT921X_ACL_BINa_VLAN_C= VID_M, (x)) + +#define YT921X_ACL_KEYb_VTAG_SVID_RANGE_EN BIT(31) +#define YT921X_ACL_KEYb_VTAG_CVID_RANGE_EN BIT(30) +#define YT921X_ACL_BINa_VTAG_CDEI BIT(31) +#define YT921X_ACL_BINa_VTAG_CPRI_M GENMASK(30, 28) +#define YT921X_ACL_BINa_VTAG_CPRI(x) FIELD_PREP(YT921X_ACL_BINa_VTAG_C= PRI_M, (x)) +#define YT921X_ACL_BINa_VTAG_SDEI BIT(27) +#define YT921X_ACL_BINa_VTAG_SPRI_M GENMASK(26, 24) +#define YT921X_ACL_BINa_VTAG_SPRI(x) FIELD_PREP(YT921X_ACL_BINa_VTAG_S= PRI_M, (x)) +#define YT921X_ACL_BINa_VTAG_SVID_M GENMASK(23, 12) +#define YT921X_ACL_BINa_VTAG_SVID(x) FIELD_PREP(YT921X_ACL_BINa_VTAG_S= VID_M, (x)) +#define YT921X_ACL_BINa_VTAG_CVID_M GENMASK(11, 0) +#define YT921X_ACL_BINa_VTAG_CVID(x) FIELD_PREP(YT921X_ACL_BINa_VTAG_C= VID_M, (x)) + +#define YT921X_ACL_KEYb_IPV4_ADDR_RANGE_EN BIT(30) +#define YT921X_ACL_BINb_IPV4_FRAG BIT(3) +#define YT921X_ACL_BINb_IPV4_L4_TYPE_M GENMASK(2, 0) +#define YT921X_ACL_BINb_IPV4_L4_TYPE(x) FIELD_PREP(YT921X_ACL_BINb_IPV4= _L4_TYPE_M, (x)) +#define YT921X_ACL_BINa_IPV4_ADDR_M GENMASK(31, 0) + +#define YT921X_ACL_BINb_IPV6_L4_TYPE_M GENMASK(2, 0) +#define YT921X_ACL_BINb_IPV6_L4_TYPE(x) FIELD_PREP(YT921X_ACL_BINb_IPV6= _L4_TYPE_M, (x)) +#define YT921X_ACL_BINa_IPV6_ADDRx_M GENMASK(31, 0) + +#define YT921X_ACL_BINb_IPV6_xA1_IP_OPTION BIT(3) + +#define YT921X_ACL_BINb_IPV6_xA2_FIRST_FRAG BIT(3) + +#define YT921X_ACL_KEYb_IPV6_xA3_ADDR_RANGE_EN BIT(30) +#define YT921X_ACL_BINb_IPV6_xA3_FRAG BIT(3) + +#define YT921X_ACL_BINb_MISC_FRAG BIT(3) +#define YT921X_ACL_BINb_MISC_L4_TYPE_M GENMASK(2, 0) +#define YT921X_ACL_BINb_MISC_L4_TYPE(x) FIELD_PREP(YT921X_ACL_BINb_MISC= _L4_TYPE_M, (x)) +#define YT921X_ACL_BINa_MISC_PPPOE_FLAG BIT(30) +#define YT921X_ACL_BINa_MISC_FIRST_FRAG BIT(29) +#define YT921X_ACL_BINa_MISC_IP_OPTION BIT(28) +#define YT921X_ACL_BINa_MISC_TCP_FLAGS_M GENMASK(27, 20) +#define YT921X_ACL_BINa_MISC_TCP_FLAGS(x) FIELD_PREP(YT921X_ACL_BINa_MI= SC_TCP_FLAGS_M, (x)) +#define YT921X_ACL_BINa_MISC_IP_PROTO_M GENMASK(19, 12) +#define YT921X_ACL_BINa_MISC_IP_PROTO(x) FIELD_PREP(YT921X_ACL_BINa_MIS= C_IP_PROTO_M, (x)) +#define YT921X_ACL_BINa_MISC_TOS_M GENMASK(11, 4) +#define YT921X_ACL_BINa_MISC_TOS(x) FIELD_PREP(YT921X_ACL_BINa_MISC_TO= S_M, (x)) +#define YT921X_ACL_BINa_MISC_L3_TYPE_M GENMASK(3, 0) +#define YT921X_ACL_BINa_MISC_L3_TYPE(x) FIELD_PREP(YT921X_ACL_BINa_MISC= _L3_TYPE_M, (x)) + +#define YT921X_ACL_KEYb_L4_DPORT_RANGE_EN BIT(31) +#define YT921X_ACL_KEYb_L4_SPORT_RANGE_EN BIT(30) +#define YT921X_ACL_BINb_L4_FRAG BIT(3) +#define YT921X_ACL_BINb_L4_TYPE_M GENMASK(2, 0) +#define YT921X_ACL_BINb_L4_TYPE(x) FIELD_PREP(YT921X_ACL_BINb_L4_TYPE_= M, (x)) +#define YT921X_ACL_BINa_L4_DPORT_M GENMASK(31, 16) +#define YT921X_ACL_BINa_L4_SPORT_M GENMASK(15, 0) + +#define YT921X_ACL_BINb_UDF_IS_IGMP BIT(0) +#define YT921X_ACL_BINa_UDF_UDF0_M GENMASK(31, 16) +#define YT921X_ACL_BINa_UDF_UDF0(x) FIELD_PREP(YT921X_ACL_BINa_UDF_UDF= 0_M, (x)) +#define YT921X_ACL_BINa_UDF_UDF1_M GENMASK(15, 0) +#define YT921X_ACL_BINa_UDF_UDF1(x) FIELD_PREP(YT921X_ACL_BINa_UDF_UDF= 1_M, (x)) + +#define YT921X_ACL_KEYb_ETHERTYPE_ETHERTYPE_RANGE_EN BIT(30) +#define YT921X_ACL_BINb_ETHERTYPE_L4_TYPE_M GENMASK(2, 0) +#define YT921X_ACL_BINb_ETHERTYPE_L4_TYPE(x) FIELD_PREP(YT921X_ACL_BINb= _ETHERTYPE_L4_TYPE_M, (x)) +#define YT921X_ACL_BINa_ETHERTYPE_ETHERTYPE_M GENMASK(15, 0) +#define YT921X_ACL_BINa_ETHERTYPE_ETHERTYPE(x) FIELD_PREP(YT921X_ACL_BIN= a_ETHERTYPE_ETHERTYPE_M, (x)) + +enum yt921x_l2_type { + YT921X_L2_TYPE_ETH, + YT921X_L2_TYPE_ETHV2, + YT921X_L2_TYPE_ETHSAP, + YT921X_L2_TYPE_ETHSNAP, +}; + +enum yt921x_l3_type { + YT921X_L3_TYPE_OTHER, + YT921X_L3_TYPE_IPV4, + YT921X_L3_TYPE_IPV6, + YT921X_L3_TYPE_ARP, + YT921X_L3_TYPE_LLDP, + YT921X_L3_TYPE_PAE, + YT921X_L3_TYPE_ERP, + YT921X_L3_TYPE_SLOW_PROTOCOL, +}; + +enum yt921x_l4_type { + YT921X_L4_TYPE_OTHER, + YT921X_L4_TYPE_TCP, + YT921X_L4_TYPE_UDP, + YT921X_L4_TYPE_UDPLITE, + YT921X_L4_TYPE_ICMP, + YT921X_L4_TYPE_IGMP, + YT921X_L4_TYPE_MLD, + YT921X_L4_TYPE_ND, +}; + #define YT921X_TPID_IGRn(x) (0x210000 + 4 * (x)) /* [0, 3] */ #define YT921X_TPID_IGR_TPID_M GENMASK(15, 0) #define YT921X_PORTn_IGR_TPID(port) (0x210010 + 4 * (port)) @@ -470,6 +718,14 @@ enum yt921x_app_selector { #define YT921X_LAG_HASH_MAC_SA BIT(2) #define YT921X_LAG_HASH_MAC_DA BIT(1) #define YT921X_LAG_HASH_SRC_PORT BIT(0) +#define YT921X_UDFn_CTRL(x) (0x210094 + 4 * (x)) +#define YT921X_UDF_CTRL_UDF_TYPE_M GENMASK(8, 7) +#define YT921X_UDF_CTRL_UDF_TYPE(x) FIELD_PREP(YT921X_UDF_CTRL_UDF_TYP= E_M, (x)) +#define YT921X_UDF_CTRL_UDF_TYPE_ETH YT921X_UDF_CTRL_UDF_TYPE(0) +#define YT921X_UDF_CTRL_UDF_TYPE_L3 YT921X_UDF_CTRL_UDF_TYPE(1) +#define YT921X_UDF_CTRL_UDF_TYPE_L4 YT921X_UDF_CTRL_UDF_TYPE(2) +#define YT921X_UDF_CTRL_UDF_OFFSET_M GENMASK(6, 0) +#define YT921X_UDF_CTRL_UDF_OFFSET(x) FIELD_PREP(YT921X_UDF_CTRL_UDF_O= FFSET_M, (x)) =20 #define YT921X_PORTn_RATE(port) (0x220000 + 4 * (port)) #define YT921X_PORT_RATE_GAP_VALUE GENMASK(4, 0) /* default 20 */ @@ -589,6 +845,11 @@ enum yt921x_fdb_entry_status { =20 #define YT921X_TAG_LEN 8 =20 +#define YT921X_ACL_BLK_NUM 48 +#define YT921X_ACL_ENT_PER_BLK 8 +#define YT921X_ACL_NUM (YT921X_ACL_BLK_NUM * YT921X_ACL_ENT_PER_BLK) +#define YT921X_UDF_NUM 8 + /* 8 internal + 2 external + 1 mcu */ #define YT921X_PORT_NUM 11 =20 @@ -647,6 +908,24 @@ struct yt921x_mib { u64 tx_oam; }; =20 +struct yt921x_acl_entry { + u32 key[2]; + u32 mask[2]; +}; + +struct yt921x_acl_rule { + unsigned long tag; + enum tc_setup_type type; + + u32 action[3]; + u8 mask; + struct yt921x_acl_entry entries[YT921X_ACL_ENT_PER_BLK]; +}; + +struct yt921x_acl_blk { + struct yt921x_acl_rule *rules[YT921X_ACL_ENT_PER_BLK]; +}; + struct yt921x_port { unsigned char index; =20 @@ -686,6 +965,11 @@ struct yt921x_priv { struct yt921x_port ports[YT921X_PORT_NUM]; =20 u16 eee_ports_mask; + + DECLARE_BITMAP(meters_map, YT921X_METER_NUM); + + u8 acl_masks[YT921X_ACL_BLK_NUM]; + struct yt921x_acl_blk *acl_blks[YT921X_ACL_BLK_NUM]; }; =20 #endif --=20 2.53.0