From patchwork Tue Nov 23 16:58:00 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Volodymyr Mytnyk X-Patchwork-Id: 12634807 X-Patchwork-Delegate: kuba@kernel.org Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 16E71C433EF for ; Tue, 23 Nov 2021 16:59:51 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S237376AbhKWRC5 (ORCPT ); Tue, 23 Nov 2021 12:02:57 -0500 Received: from mail-eopbgr60116.outbound.protection.outlook.com ([40.107.6.116]:58190 "EHLO EUR04-DB3-obe.outbound.protection.outlook.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S237245AbhKWRC4 (ORCPT ); Tue, 23 Nov 2021 12:02:56 -0500 ARC-Seal: i=1; a=rsa-sha256; s=arcselector9901; d=microsoft.com; cv=none; b=l8h5FOtak12l1f/MPviNc4aA+RprmJD9GyFxnxdRmOkB05xUMDxXFG2yovQI4Y7GGRqyhoWbG7Omt+asqMES9IIAHWEUXST941MVXKjUDeTRo6+BZvSuGLbfC53cBDiRt7JB9Sai7YXTfS1NCJBVaXI4MAU2pJzgx+/0x9w4/TylnxVP0YPKGt/f+SqeGklS5oYrFIIeNbRiebztkOFoXOpiBv7mVRuOLh9PUTrnGHCNn+4fUbwiMYlTOjyQJi81pB3L2HidfCG7DeKBO0BFLq+J/Bbe8gqjEtRzE23KjUKTSB9g9NYYdTSMoTsF+fLNOHsZ1j5Qcc24Fga+Zcy4iQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=arcselector9901; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-AntiSpam-MessageData-ChunkCount:X-MS-Exchange-AntiSpam-MessageData-0:X-MS-Exchange-AntiSpam-MessageData-1; bh=On0ZRzKuUgikWNugQRKc8y/VlqcV8mUA3edCbp+/xm0=; b=XdymooWCfV0EGCvuJdkcNyWWFmCxaez1DVvIAmu7gu/54Ky9y2UXkzdUfDZCSTQ6iCpODjR8Oq6wk3C0WtgJLshzcBr0ZtWkP8uTaYgjEtPGc4D+UHKg1Hu08vFRupuY9dpU7j2Nbu+KIkIA1YPgwxmfT7GEL+3HSbQCdBo1fntAAnFrxT97l9QsVcltkX3HUsDeU4tSJgbeDvdwr7k1YcOWUfncS5UYTG/Uf5/gUD9UtSQL34T6sdWdGyXNUxNJOlj8Vl3XY1f8K0cENYY26AesmmiwIhtjjkm9Ry+Zl/mBzL5J85AxDCZxkYoBefk/j/du9U8DVhVcTFCw4tFy1Q== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=pass smtp.mailfrom=plvision.eu; dmarc=pass action=none header.from=plvision.eu; dkim=pass header.d=plvision.eu; arc=none DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=plvision.eu; s=selector2; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=On0ZRzKuUgikWNugQRKc8y/VlqcV8mUA3edCbp+/xm0=; b=TVN///F/CVQ9HdcUnxjjDrw8aaW2t/LnruVEheRwdnxDsc3d8fhmjW4mkO2vi60S81/x2u8BC3AFMY4jc09lGdcFc5v8h2hkI85o6GV4/WuvlH09USyosxqG1am4mTE/30Pxvu10Rxfih13pPOkImUMYvldVPWhtUlx7I15nC+U= Authentication-Results: dkim=none (message not signed) header.d=none;dmarc=none action=none header.from=plvision.eu; Received: from VI1P190MB0734.EURP190.PROD.OUTLOOK.COM (2603:10a6:800:123::23) by VE1P190MB0830.EURP190.PROD.OUTLOOK.COM (2603:10a6:800:1a9::5) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.4713.24; Tue, 23 Nov 2021 16:59:43 +0000 Received: from VI1P190MB0734.EURP190.PROD.OUTLOOK.COM ([fe80::e15a:32ff:b93c:d136]) by VI1P190MB0734.EURP190.PROD.OUTLOOK.COM ([fe80::e15a:32ff:b93c:d136%4]) with mapi id 15.20.4713.026; Tue, 23 Nov 2021 16:59:43 +0000 From: Volodymyr Mytnyk To: netdev@vger.kernel.org Cc: Taras Chornyi , Mickey Rachamim , Serhiy Pshyk , Volodymyr Mytnyk , Taras Chornyi , "David S. Miller" , Jakub Kicinski , linux-kernel@vger.kernel.org, Yevhen Orlov Subject: [PATCH net-next 1/3] net: prestera: acl: migrate to new vTCAM api Date: Tue, 23 Nov 2021 18:58:00 +0200 Message-Id: <1637686684-2492-2-git-send-email-volodymyr.mytnyk@plvision.eu> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1637686684-2492-1-git-send-email-volodymyr.mytnyk@plvision.eu> References: <1637686684-2492-1-git-send-email-volodymyr.mytnyk@plvision.eu> X-ClientProxiedBy: AS8PR04CA0203.eurprd04.prod.outlook.com (2603:10a6:20b:2f3::28) To VI1P190MB0734.EURP190.PROD.OUTLOOK.COM (2603:10a6:800:123::23) MIME-Version: 1.0 Received: from vmytnykub.x.ow.s (217.20.186.93) by AS8PR04CA0203.eurprd04.prod.outlook.com (2603:10a6:20b:2f3::28) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256) id 15.20.4713.19 via Frontend Transport; Tue, 23 Nov 2021 16:59:42 +0000 X-MS-PublicTrafficType: Email X-MS-Office365-Filtering-Correlation-Id: 486c8257-2b0c-462c-ea12-08d9aea2a541 X-MS-TrafficTypeDiagnostic: VE1P190MB0830: X-Microsoft-Antispam-PRVS: X-MS-Oob-TLC-OOBClassifiers: OLM:3276; X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0; X-Microsoft-Antispam-Message-Info: bQ2SgkZXEhPzEOWUIVDrrPd6xqdBUl/dk1UG+uUeHuAfQKM8LH3Kzj7A0ZLi/u2VDNnlbLLEPQKaQNzkNyUIdjL1mU9hntxARXGJ34kc92VUvNs9UiIWMtpZo64BetbCXQJ4uCnWBMVlGzL7Y3tL1X08KSBZbzahBkUTEZzxTHQ5wk7lZSszwbjDZ5AFqP3JpG6d1G9XeUtbVG43pzHII/e3N5ekm1p+3MF9YBH0j9jiYunY0Ot9i+2nLrzsSzIaAws7F5sN6OK/+OArAXeqJ9aGECbqFPsIw25/CKglbktvTM3WFbVnzBq6rSXOipg4uFzVNKdPwDXHMi+EP4PYkh5OXGT0bBz+21TEDTjv+QEF0OjMund6QEAMnHL4wuQ61MLJacEff9iulzNtzmHzX697MRXcfFcOoRwtPWHlD/mK//DeorHKbfN6yEXWCi2oOO7dbakAseTiSMIYBEH8SoH6Laq29M1l4YRrwCwZ1RTS3HMxtvgIusjy2DnDQOwxA6crypGj0aqLd57R2igQh0Cr3Ofv41zCI5ByroMvrN+FbBlAa6s1MEPLastc/1J59ns2tqSYBdnzU5S52kTu78fxF92pROdFJrs99jGvzhU3BSIlucQctxmMhvakp9L1CWPD6RiCK4wAnx9JSbBycHyVUf7dhdo+S4RphC5ScTUSyQqOzVrgiXDjyIK3vMY6DQIfz4bWX/YCI4qWQ4c/fw== X-Forefront-Antispam-Report: CIP:255.255.255.255;CTRY:;LANG:en;SCL:1;SRV:;IPV:NLI;SFV:NSPM;H:VI1P190MB0734.EURP190.PROD.OUTLOOK.COM;PTR:;CAT:NONE;SFS:(136003)(376002)(39830400003)(366004)(396003)(346002)(107886003)(36756003)(26005)(956004)(2616005)(6666004)(83380400001)(66946007)(8936002)(8676002)(6512007)(38350700002)(66556008)(66476007)(52116002)(316002)(186003)(30864003)(2906002)(6916009)(38100700002)(44832011)(86362001)(54906003)(4326008)(5660300002)(508600001)(6486002)(6506007)(559001)(579004);DIR:OUT;SFP:1102; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 1 X-MS-Exchange-AntiSpam-MessageData-0: +RzNdeHilHeNy5CsuzDcKKw5lVugCqDIq7y4nDzVOrELgLgAKH8T8ZcXD6A4b4ouqf9NF0Euep8eGce78T3GQZbBv8dzaALgXkWmiSbwsGhokyZ0aVlW0Lkt+Mo9bW7R+7AGrSkUMTPrYvm5AoVoUlqdWT8a7Arfwz1HriGK5DnNlAUrqnuasT47utOzFEDpLoIWpUPr45tNRt0mK9s49x7LfcFEQ/taOXq7ecwb6JN0IKp3SvYQomZuBTcEewMlQEIqlW4FoXECzDd5uMHIgTyo7+F3yqzjwPbHl4ioH5uspO0WswflfxUAy9JibPfnLJyLDBAEe7YC+Kk6eLQ8S2YEgt3W1h+R/dsmWbLpLPnI5/UIe/MXX0Kd/er9/rP4dLajkfCqea6MxGL90otZLfxrdnGRjBGjgHrafM4szlRg/TUsAThXrirRUoeqgtWjwM8A4rLxow2F0DS4VahFFTztFjltZax0KfebtaOLKKpBBLim1NiKPbek/PqOY7S0v8CRHd18SancFnz/xYKWG0KjIrg7w/NEHqGIETN11lr5x9FqpWXplCuxVVoMr0fq6O6i3hi7xO/+Jm7oPsEPhzIODRafKDwMQkpao3zQ3vRMZ/x03vzUNWU3IIDzawyHYXIEpRDNmAk5/wU/t56riunTcCtFK08f4NhniHH2eGmZ/CqfVIVhdlenWP+KRNZEXZYTAbmlrUOAt+VOCwMpBV7+WHkJCtkpaj5ztunB0RD9xX8Q/NuGmsoME3MYhcninXRVFn2/n0h7QRso9KR1xlg/s8CaSfAki3xSuOz243RNTrxsDP2NrrLYoQ4o4ivRfwBFiOy9NG7xOSL5mf4S9iCY0A9QHbBl+QoBWjNa6SQykVofkji/LwhlasgcKhFZTz8E072kNXsXWZJ7MuXHEwsGnnDrTvxhCHFzxPcuJoiA4GMgNolHTASsckzMD3UHFt4Xx9B7/OfchKKL5CI98CxQTC20k5dlQ2NpSFkpvlgnB42lre2xhKba0/riDamBfUkw4vqVo/7VdAzkIRONzZjoh+rLfv76TP60qV52nC33FqboDpsn0Aull8IOhzsYHuzpwMXf80GUCDvBSFhG69ArCYurk7sL90AOCvWl9nBtheTjVfLIy35OYscJfIYE5FBPh9eGAE1dTAriYdjUIqLcexKMfDaDXMiMLzyeg5/gQYEbOt6NuhBaJbb62eIdLLyuonruWeepkRffuECmC028cvncBX5zUgX1tTP93YrrzfX+6wJNGLaItcqByXK5rUTfv5xOwUECtjfJbHd7D/OjCTqNRbnwW3xm+xn/UknwrAvOJa7mkexXg5ENzmmPgl2n4PTfCAtATkpz9thHWBSSOSVOAlnGvRgd/7qPf6B25lYQwctIPvLtaOOqO2jumyOGU08bE78ZCf7PGQetOu8h0lqXLtwmK3r+igt5P2CCrVLIGaLCNJAh4m96QQ3X75GjUUMi4Q6SsxZnPi7UI+6lO+RLXh2I81xRp0e8f5p0PDdFssqe/8raM5KlQDIH15Sw/xIwFYCSvFqSNJiCB7vgz8iPCq0xTofzi83VuFQzmlPH8h4Q/qlC47rP3HqBhqr+B9HnsxfM/hbtiGjszW79lzpFJHGNh9mohOrEddmcraQp5VkjH1FHaFmO1+DnEM4XHObi9rOLSE3ZDdYWmQ== X-OriginatorOrg: plvision.eu X-MS-Exchange-CrossTenant-Network-Message-Id: 486c8257-2b0c-462c-ea12-08d9aea2a541 X-MS-Exchange-CrossTenant-AuthSource: VI1P190MB0734.EURP190.PROD.OUTLOOK.COM X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 23 Nov 2021 16:59:43.2600 (UTC) X-MS-Exchange-CrossTenant-FromEntityHeader: Hosted X-MS-Exchange-CrossTenant-Id: 03707b74-30f3-46b6-a0e0-ff0a7438c9c4 X-MS-Exchange-CrossTenant-MailboxType: HOSTED X-MS-Exchange-CrossTenant-UserPrincipalName: wV0jYPulgR6wejAJYaCsGrnA/Jw4MxuxZZ7xRdsGNYdhvecohXfdEIDoDeWJKRmDj0/Z8s+1ej4j/236Wc30kh8+V4ooaDtpjSABxbSQwZk= X-MS-Exchange-Transport-CrossTenantHeadersStamped: VE1P190MB0830 Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org X-Patchwork-Delegate: kuba@kernel.org From: Volodymyr Mytnyk - Add new vTCAM HW API to configure HW ACLs. - Migrate acl to use new vTCAM HW API. - No counter support in this patch-set. Co-developed-by: Yevhen Orlov Signed-off-by: Yevhen Orlov Signed-off-by: Volodymyr Mytnyk --- .../net/ethernet/marvell/prestera/prestera_acl.c | 661 +++++++++++++++------ .../net/ethernet/marvell/prestera/prestera_acl.h | 203 ++++--- .../net/ethernet/marvell/prestera/prestera_flow.c | 109 +++- .../net/ethernet/marvell/prestera/prestera_flow.h | 16 + .../ethernet/marvell/prestera/prestera_flower.c | 288 +++++---- .../ethernet/marvell/prestera/prestera_flower.h | 12 +- .../net/ethernet/marvell/prestera/prestera_hw.c | 361 +++++------ .../net/ethernet/marvell/prestera/prestera_hw.h | 41 +- .../net/ethernet/marvell/prestera/prestera_span.c | 1 + 9 files changed, 1024 insertions(+), 668 deletions(-) diff --git a/drivers/net/ethernet/marvell/prestera/prestera_acl.c b/drivers/net/ethernet/marvell/prestera/prestera_acl.c index 83c75ffb1a1c..f0119d72427f 100644 --- a/drivers/net/ethernet/marvell/prestera/prestera_acl.c +++ b/drivers/net/ethernet/marvell/prestera/prestera_acl.c @@ -1,37 +1,75 @@ // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0 -/* Copyright (c) 2020 Marvell International Ltd. All rights reserved */ +/* Copyright (c) 2020-2021 Marvell International Ltd. All rights reserved */ #include -#include "prestera.h" -#include "prestera_hw.h" #include "prestera_acl.h" -#include "prestera_span.h" +#include "prestera_flow.h" +#include "prestera_hw.h" +#include "prestera.h" + +#define ACL_KEYMASK_SIZE \ + (sizeof(__be32) * __PRESTERA_ACL_RULE_MATCH_TYPE_MAX) struct prestera_acl { struct prestera_switch *sw; + struct list_head vtcam_list; struct list_head rules; + struct rhashtable ruleset_ht; + struct rhashtable acl_rule_entry_ht; + struct idr uid; +}; + +struct prestera_acl_ruleset_ht_key { + struct prestera_flow_block *block; +}; + +struct prestera_acl_rule_entry { + struct rhash_head ht_node; + struct prestera_acl_rule_entry_key key; + u32 hw_id; + u32 vtcam_id; + struct { + struct { + u8 valid:1; + } accept, drop, trap; + }; }; struct prestera_acl_ruleset { + struct rhash_head ht_node; /* Member of acl HT */ + struct prestera_acl_ruleset_ht_key ht_key; struct rhashtable rule_ht; - struct prestera_switch *sw; - u16 id; + struct prestera_acl *acl; + unsigned long rule_count; + refcount_t refcount; + void *keymask; + bool offload; + u32 vtcam_id; + u16 pcl_id; }; -struct prestera_acl_rule { - struct rhash_head ht_node; +struct prestera_acl_uid_entry { struct list_head list; - struct list_head match_list; - struct list_head action_list; - struct prestera_flow_block *block; - unsigned long cookie; - u32 priority; - u8 n_actions; - u8 n_matches; + u8 id; +}; + +struct prestera_acl_vtcam { + struct list_head list; + __be32 keymask[__PRESTERA_ACL_RULE_MATCH_TYPE_MAX]; + bool is_keymask_set; + refcount_t refcount; + u8 lookup; u32 id; }; +static const struct rhashtable_params prestera_acl_ruleset_ht_params = { + .key_len = sizeof(struct prestera_acl_ruleset_ht_key), + .key_offset = offsetof(struct prestera_acl_ruleset, ht_key), + .head_offset = offsetof(struct prestera_acl_ruleset, ht_node), + .automatic_shrinking = true, +}; + static const struct rhashtable_params prestera_acl_rule_ht_params = { .key_len = sizeof(unsigned long), .key_offset = offsetof(struct prestera_acl_rule, cookie), @@ -39,28 +77,48 @@ static const struct rhashtable_params prestera_acl_rule_ht_params = { .automatic_shrinking = true, }; +static const struct rhashtable_params __prestera_acl_rule_entry_ht_params = { + .key_offset = offsetof(struct prestera_acl_rule_entry, key), + .head_offset = offsetof(struct prestera_acl_rule_entry, ht_node), + .key_len = sizeof(struct prestera_acl_rule_entry_key), + .automatic_shrinking = true, +}; + static struct prestera_acl_ruleset * -prestera_acl_ruleset_create(struct prestera_switch *sw) +prestera_acl_ruleset_create(struct prestera_acl *acl, + struct prestera_flow_block *block) { struct prestera_acl_ruleset *ruleset; int err; + u32 uid; ruleset = kzalloc(sizeof(*ruleset), GFP_KERNEL); if (!ruleset) return ERR_PTR(-ENOMEM); + ruleset->acl = acl; + ruleset->ht_key.block = block; + refcount_set(&ruleset->refcount, 1); + err = rhashtable_init(&ruleset->rule_ht, &prestera_acl_rule_ht_params); if (err) goto err_rhashtable_init; - err = prestera_hw_acl_ruleset_create(sw, &ruleset->id); + err = idr_alloc_u32(&acl->uid, NULL, &uid, U8_MAX, GFP_KERNEL); if (err) goto err_ruleset_create; - ruleset->sw = sw; + /* make pcl-id based on uid */ + ruleset->pcl_id = (u8)uid; + err = rhashtable_insert_fast(&acl->ruleset_ht, &ruleset->ht_node, + prestera_acl_ruleset_ht_params); + if (err) + goto err_ruleset_ht_insert; return ruleset; +err_ruleset_ht_insert: + idr_remove(&acl->uid, uid); err_ruleset_create: rhashtable_destroy(&ruleset->rule_ht); err_rhashtable_init: @@ -68,117 +126,176 @@ prestera_acl_ruleset_create(struct prestera_switch *sw) return ERR_PTR(err); } -static void prestera_acl_ruleset_destroy(struct prestera_acl_ruleset *ruleset) +int prestera_acl_ruleset_keymask_set(struct prestera_acl_ruleset *ruleset, + void *keymask) { - prestera_hw_acl_ruleset_del(ruleset->sw, ruleset->id); - rhashtable_destroy(&ruleset->rule_ht); - kfree(ruleset); + void *__keymask; + + if (!keymask || !ruleset) + return -EINVAL; + + __keymask = kmalloc(ACL_KEYMASK_SIZE, GFP_KERNEL); + if (!__keymask) + return -ENOMEM; + + memcpy(__keymask, keymask, ACL_KEYMASK_SIZE); + ruleset->keymask = __keymask; + + return 0; } -struct prestera_flow_block * -prestera_acl_block_create(struct prestera_switch *sw, struct net *net) +int prestera_acl_ruleset_offload(struct prestera_acl_ruleset *ruleset) { - struct prestera_flow_block *block; + u32 vtcam_id; + int err; - block = kzalloc(sizeof(*block), GFP_KERNEL); - if (!block) - return NULL; - INIT_LIST_HEAD(&block->binding_list); - block->net = net; - block->sw = sw; - - block->ruleset = prestera_acl_ruleset_create(sw); - if (IS_ERR(block->ruleset)) { - kfree(block); - return NULL; - } + if (ruleset->offload) + return -EEXIST; - return block; + err = prestera_acl_vtcam_id_get(ruleset->acl, 0, + ruleset->keymask, &vtcam_id); + if (err) + return err; + + ruleset->vtcam_id = vtcam_id; + ruleset->offload = true; + return 0; } -void prestera_acl_block_destroy(struct prestera_flow_block *block) +static void prestera_acl_ruleset_destroy(struct prestera_acl_ruleset *ruleset) { - prestera_acl_ruleset_destroy(block->ruleset); - WARN_ON(!list_empty(&block->binding_list)); - kfree(block); + struct prestera_acl *acl = ruleset->acl; + u8 uid = ruleset->pcl_id & PRESTERA_ACL_KEYMASK_PCL_ID_USER; + + rhashtable_remove_fast(&acl->ruleset_ht, &ruleset->ht_node, + prestera_acl_ruleset_ht_params); + + if (ruleset->offload) + WARN_ON(prestera_acl_vtcam_id_put(acl, ruleset->vtcam_id)); + + idr_remove(&acl->uid, uid); + + rhashtable_destroy(&ruleset->rule_ht); + kfree(ruleset->keymask); + kfree(ruleset); } -static struct prestera_flow_block_binding * -prestera_acl_block_lookup(struct prestera_flow_block *block, - struct prestera_port *port) +static struct prestera_acl_ruleset * +__prestera_acl_ruleset_lookup(struct prestera_acl *acl, + struct prestera_flow_block *block) { - struct prestera_flow_block_binding *binding; + struct prestera_acl_ruleset_ht_key ht_key; - list_for_each_entry(binding, &block->binding_list, list) - if (binding->port == port) - return binding; - - return NULL; + memset(&ht_key, 0, sizeof(ht_key)); + ht_key.block = block; + return rhashtable_lookup_fast(&acl->ruleset_ht, &ht_key, + prestera_acl_ruleset_ht_params); } -int prestera_acl_block_bind(struct prestera_flow_block *block, - struct prestera_port *port) +struct prestera_acl_ruleset * +prestera_acl_ruleset_lookup(struct prestera_acl *acl, + struct prestera_flow_block *block) { - struct prestera_flow_block_binding *binding; - int err; + struct prestera_acl_ruleset *ruleset; - if (WARN_ON(prestera_acl_block_lookup(block, port))) - return -EEXIST; + ruleset = __prestera_acl_ruleset_lookup(acl, block); + if (!ruleset) + return ERR_PTR(-ENOENT); - binding = kzalloc(sizeof(*binding), GFP_KERNEL); - if (!binding) - return -ENOMEM; - binding->span_id = PRESTERA_SPAN_INVALID_ID; - binding->port = port; + refcount_inc(&ruleset->refcount); + return ruleset; +} - err = prestera_hw_acl_port_bind(port, block->ruleset->id); - if (err) - goto err_rules_bind; +struct prestera_acl_ruleset * +prestera_acl_ruleset_get(struct prestera_acl *acl, + struct prestera_flow_block *block) +{ + struct prestera_acl_ruleset *ruleset; - list_add(&binding->list, &block->binding_list); - return 0; + ruleset = __prestera_acl_ruleset_lookup(acl, block); + if (ruleset) { + refcount_inc(&ruleset->refcount); + return ruleset; + } -err_rules_bind: - kfree(binding); - return err; + return prestera_acl_ruleset_create(acl, block); } -int prestera_acl_block_unbind(struct prestera_flow_block *block, - struct prestera_port *port) +void prestera_acl_ruleset_put(struct prestera_acl_ruleset *ruleset) { - struct prestera_flow_block_binding *binding; - - binding = prestera_acl_block_lookup(block, port); - if (!binding) - return -ENOENT; + if (!refcount_dec_and_test(&ruleset->refcount)) + return; - list_del(&binding->list); + prestera_acl_ruleset_destroy(ruleset); +} - prestera_hw_acl_port_unbind(port, block->ruleset->id); +int prestera_acl_ruleset_bind(struct prestera_acl_ruleset *ruleset, + struct prestera_port *port) +{ + struct prestera_acl_iface iface = { + .type = PRESTERA_ACL_IFACE_TYPE_PORT, + .port = port + }; - kfree(binding); - return 0; + return prestera_hw_vtcam_iface_bind(port->sw, &iface, ruleset->vtcam_id, + ruleset->pcl_id); } -struct prestera_acl_ruleset * -prestera_acl_block_ruleset_get(struct prestera_flow_block *block) +int prestera_acl_ruleset_unbind(struct prestera_acl_ruleset *ruleset, + struct prestera_port *port) { - return block->ruleset; + struct prestera_acl_iface iface = { + .type = PRESTERA_ACL_IFACE_TYPE_PORT, + .port = port + }; + + return prestera_hw_vtcam_iface_unbind(port->sw, &iface, + ruleset->vtcam_id); } -u16 prestera_acl_rule_ruleset_id_get(const struct prestera_acl_rule *rule) +static int prestera_acl_ruleset_block_bind(struct prestera_acl_ruleset *ruleset, + struct prestera_flow_block *block) { - return rule->block->ruleset->id; + struct prestera_flow_block_binding *binding; + int err; + + block->ruleset_zero = ruleset; + list_for_each_entry(binding, &block->binding_list, list) { + err = prestera_acl_ruleset_bind(ruleset, binding->port); + if (err) + goto rollback; + } + return 0; + +rollback: + list_for_each_entry_continue_reverse(binding, &block->binding_list, + list) + err = prestera_acl_ruleset_unbind(ruleset, binding->port); + block->ruleset_zero = NULL; + + return err; } -struct net *prestera_acl_block_net(struct prestera_flow_block *block) +static void +prestera_acl_ruleset_block_unbind(struct prestera_acl_ruleset *ruleset, + struct prestera_flow_block *block) { - return block->net; + struct prestera_flow_block_binding *binding; + + list_for_each_entry(binding, &block->binding_list, list) + prestera_acl_ruleset_unbind(ruleset, binding->port); + block->ruleset_zero = NULL; } -struct prestera_switch *prestera_acl_block_sw(struct prestera_flow_block *block) +void +prestera_acl_rule_keymask_pcl_id_set(struct prestera_acl_rule *rule, u16 pcl_id) { - return block->sw; + struct prestera_acl_match *r_match = &rule->re_key.match; + __be16 pcl_id_mask = htons(PRESTERA_ACL_KEYMASK_PCL_ID); + __be16 pcl_id_key = htons(pcl_id); + + rule_match_set(r_match->key, PCL_ID, pcl_id_key); + rule_match_set(r_match->mask, PCL_ID, pcl_id_mask); } struct prestera_acl_rule * @@ -189,8 +306,13 @@ prestera_acl_rule_lookup(struct prestera_acl_ruleset *ruleset, prestera_acl_rule_ht_params); } +bool prestera_acl_ruleset_is_offload(struct prestera_acl_ruleset *ruleset) +{ + return ruleset->offload; +} + struct prestera_acl_rule * -prestera_acl_rule_create(struct prestera_flow_block *block, +prestera_acl_rule_create(struct prestera_acl_ruleset *ruleset, unsigned long cookie) { struct prestera_acl_rule *rule; @@ -199,178 +321,353 @@ prestera_acl_rule_create(struct prestera_flow_block *block, if (!rule) return ERR_PTR(-ENOMEM); - INIT_LIST_HEAD(&rule->match_list); - INIT_LIST_HEAD(&rule->action_list); + rule->ruleset = ruleset; rule->cookie = cookie; - rule->block = block; + + refcount_inc(&ruleset->refcount); return rule; } -struct list_head * -prestera_acl_rule_match_list_get(struct prestera_acl_rule *rule) +void prestera_acl_rule_priority_set(struct prestera_acl_rule *rule, + u32 priority) { - return &rule->match_list; + rule->priority = priority; } -struct list_head * -prestera_acl_rule_action_list_get(struct prestera_acl_rule *rule) +void prestera_acl_rule_destroy(struct prestera_acl_rule *rule) { - return &rule->action_list; + prestera_acl_ruleset_put(rule->ruleset); + kfree(rule); } -int prestera_acl_rule_action_add(struct prestera_acl_rule *rule, - struct prestera_acl_rule_action_entry *entry) +int prestera_acl_rule_add(struct prestera_switch *sw, + struct prestera_acl_rule *rule) { - struct prestera_acl_rule_action_entry *a_entry; + int err; + struct prestera_acl_ruleset *ruleset = rule->ruleset; + struct prestera_flow_block *block = ruleset->ht_key.block; - a_entry = kmalloc(sizeof(*a_entry), GFP_KERNEL); - if (!a_entry) - return -ENOMEM; + /* try to add rule to hash table first */ + err = rhashtable_insert_fast(&ruleset->rule_ht, &rule->ht_node, + prestera_acl_rule_ht_params); + if (err) + goto err_ht_insert; - memcpy(a_entry, entry, sizeof(*entry)); - list_add(&a_entry->list, &rule->action_list); + prestera_acl_rule_keymask_pcl_id_set(rule, ruleset->pcl_id); + rule->re_arg.vtcam_id = ruleset->vtcam_id; + rule->re_key.prio = rule->priority; + + rule->re = prestera_acl_rule_entry_find(sw->acl, &rule->re_key); + err = WARN_ON(rule->re) ? -EEXIST : 0; + if (err) + goto err_rule_add; - rule->n_actions++; + rule->re = prestera_acl_rule_entry_create(sw->acl, &rule->re_key, + &rule->re_arg); + err = !rule->re ? -EINVAL : 0; + if (err) + goto err_rule_add; + + /* bind the block (all ports) to chain index 0 */ + if (!ruleset->rule_count) { + err = prestera_acl_ruleset_block_bind(ruleset, block); + if (err) + goto err_acl_block_bind; + } + + list_add_tail(&rule->list, &sw->acl->rules); + ruleset->rule_count++; return 0; + +err_acl_block_bind: + prestera_acl_rule_entry_destroy(sw->acl, rule->re); +err_rule_add: + rule->re = NULL; + rhashtable_remove_fast(&ruleset->rule_ht, &rule->ht_node, + prestera_acl_rule_ht_params); +err_ht_insert: + return err; +} + +void prestera_acl_rule_del(struct prestera_switch *sw, + struct prestera_acl_rule *rule) +{ + struct prestera_acl_ruleset *ruleset = rule->ruleset; + struct prestera_flow_block *block = ruleset->ht_key.block; + + rhashtable_remove_fast(&ruleset->rule_ht, &rule->ht_node, + prestera_acl_rule_ht_params); + ruleset->rule_count--; + list_del(&rule->list); + + prestera_acl_rule_entry_destroy(sw->acl, rule->re); + + /* unbind block (all ports) */ + if (!ruleset->rule_count) + prestera_acl_ruleset_block_unbind(ruleset, block); } -u8 prestera_acl_rule_action_len(struct prestera_acl_rule *rule) +int prestera_acl_rule_get_stats(struct prestera_acl *acl, + struct prestera_acl_rule *rule, + u64 *packets, u64 *bytes, u64 *last_use) { - return rule->n_actions; + *last_use = jiffies; + *packets = 0; + *bytes = 0; + + return 0; } -u32 prestera_acl_rule_priority_get(struct prestera_acl_rule *rule) +struct prestera_acl_rule_entry * +prestera_acl_rule_entry_find(struct prestera_acl *acl, + struct prestera_acl_rule_entry_key *key) { - return rule->priority; + struct prestera_acl_rule_entry *e; + + e = rhashtable_lookup_fast(&acl->acl_rule_entry_ht, key, + __prestera_acl_rule_entry_ht_params); + return IS_ERR(e) ? NULL : e; } -void prestera_acl_rule_priority_set(struct prestera_acl_rule *rule, - u32 priority) +static int __prestera_acl_rule_entry2hw_del(struct prestera_switch *sw, + struct prestera_acl_rule_entry *e) { - rule->priority = priority; + return prestera_hw_vtcam_rule_del(sw, e->vtcam_id, e->hw_id); } -int prestera_acl_rule_match_add(struct prestera_acl_rule *rule, - struct prestera_acl_rule_match_entry *entry) +static int __prestera_acl_rule_entry2hw_add(struct prestera_switch *sw, + struct prestera_acl_rule_entry *e) { - struct prestera_acl_rule_match_entry *m_entry; + struct prestera_acl_hw_action_info act_hw[PRESTERA_ACL_RULE_ACTION_MAX]; + int act_num; - m_entry = kmalloc(sizeof(*m_entry), GFP_KERNEL); - if (!m_entry) - return -ENOMEM; + memset(&act_hw, 0, sizeof(act_hw)); + act_num = 0; - memcpy(m_entry, entry, sizeof(*entry)); - list_add(&m_entry->list, &rule->match_list); + /* accept */ + if (e->accept.valid) { + act_hw[act_num].id = PRESTERA_ACL_RULE_ACTION_ACCEPT; + act_num++; + } + /* drop */ + if (e->drop.valid) { + act_hw[act_num].id = PRESTERA_ACL_RULE_ACTION_DROP; + act_num++; + } + /* trap */ + if (e->trap.valid) { + act_hw[act_num].id = PRESTERA_ACL_RULE_ACTION_TRAP; + act_num++; + } - rule->n_matches++; - return 0; + return prestera_hw_vtcam_rule_add(sw, e->vtcam_id, e->key.prio, + e->key.match.key, e->key.match.mask, + act_hw, act_num, &e->hw_id); } -u8 prestera_acl_rule_match_len(struct prestera_acl_rule *rule) +static void +__prestera_acl_rule_entry_act_destruct(struct prestera_switch *sw, + struct prestera_acl_rule_entry *e) { - return rule->n_matches; + /* destroy action entry */ } -void prestera_acl_rule_destroy(struct prestera_acl_rule *rule) +void prestera_acl_rule_entry_destroy(struct prestera_acl *acl, + struct prestera_acl_rule_entry *e) { - struct prestera_acl_rule_action_entry *a_entry; - struct prestera_acl_rule_match_entry *m_entry; - struct list_head *pos, *n; + int ret; - list_for_each_safe(pos, n, &rule->match_list) { - m_entry = list_entry(pos, typeof(*m_entry), list); - list_del(pos); - kfree(m_entry); - } + rhashtable_remove_fast(&acl->acl_rule_entry_ht, &e->ht_node, + __prestera_acl_rule_entry_ht_params); - list_for_each_safe(pos, n, &rule->action_list) { - a_entry = list_entry(pos, typeof(*a_entry), list); - list_del(pos); - kfree(a_entry); - } + ret = __prestera_acl_rule_entry2hw_del(acl->sw, e); + WARN_ON(ret && ret != -ENODEV); - kfree(rule); + __prestera_acl_rule_entry_act_destruct(acl->sw, e); + kfree(e); } -int prestera_acl_rule_add(struct prestera_switch *sw, - struct prestera_acl_rule *rule) +static int +__prestera_acl_rule_entry_act_construct(struct prestera_switch *sw, + struct prestera_acl_rule_entry *e, + struct prestera_acl_rule_entry_arg *arg) +{ + /* accept */ + e->accept.valid = arg->accept.valid; + /* drop */ + e->drop.valid = arg->drop.valid; + /* trap */ + e->trap.valid = arg->trap.valid; + + return 0; +} + +struct prestera_acl_rule_entry * +prestera_acl_rule_entry_create(struct prestera_acl *acl, + struct prestera_acl_rule_entry_key *key, + struct prestera_acl_rule_entry_arg *arg) { - u32 rule_id; + struct prestera_acl_rule_entry *e; int err; - /* try to add rule to hash table first */ - err = rhashtable_insert_fast(&rule->block->ruleset->rule_ht, - &rule->ht_node, - prestera_acl_rule_ht_params); - if (err) - return err; + e = kzalloc(sizeof(*e), GFP_KERNEL); + if (!e) + goto err_kzalloc; - /* add rule to hw */ - err = prestera_hw_acl_rule_add(sw, rule, &rule_id); + memcpy(&e->key, key, sizeof(*key)); + e->vtcam_id = arg->vtcam_id; + err = __prestera_acl_rule_entry_act_construct(acl->sw, e, arg); if (err) - goto err_rule_add; + goto err_act_construct; - rule->id = rule_id; + err = __prestera_acl_rule_entry2hw_add(acl->sw, e); + if (err) + goto err_hw_add; - list_add_tail(&rule->list, &sw->acl->rules); + err = rhashtable_insert_fast(&acl->acl_rule_entry_ht, &e->ht_node, + __prestera_acl_rule_entry_ht_params); + if (err) + goto err_ht_insert; - return 0; + return e; -err_rule_add: - rhashtable_remove_fast(&rule->block->ruleset->rule_ht, &rule->ht_node, - prestera_acl_rule_ht_params); - return err; +err_ht_insert: + WARN_ON(__prestera_acl_rule_entry2hw_del(acl->sw, e)); +err_hw_add: + __prestera_acl_rule_entry_act_destruct(acl->sw, e); +err_act_construct: + kfree(e); +err_kzalloc: + return NULL; } -void prestera_acl_rule_del(struct prestera_switch *sw, - struct prestera_acl_rule *rule) +int prestera_acl_vtcam_id_get(struct prestera_acl *acl, u8 lookup, + void *keymask, u32 *vtcam_id) { - rhashtable_remove_fast(&rule->block->ruleset->rule_ht, &rule->ht_node, - prestera_acl_rule_ht_params); - list_del(&rule->list); - prestera_hw_acl_rule_del(sw, rule->id); + struct prestera_acl_vtcam *vtcam; + u32 new_vtcam_id; + int err; + + /* find the vtcam that suits keymask. We do not expect to have + * a big number of vtcams, so, the list type for vtcam list is + * fine for now + */ + list_for_each_entry(vtcam, &acl->vtcam_list, list) { + if (lookup != vtcam->lookup) + continue; + + if (!keymask && !vtcam->is_keymask_set) { + refcount_inc(&vtcam->refcount); + goto vtcam_found; + } + + if (keymask && vtcam->is_keymask_set && + !memcmp(keymask, vtcam->keymask, sizeof(vtcam->keymask))) { + refcount_inc(&vtcam->refcount); + goto vtcam_found; + } + } + + /* vtcam not found, try to create new one */ + vtcam = kzalloc(sizeof(*vtcam), GFP_KERNEL); + if (!vtcam) + return -ENOMEM; + + err = prestera_hw_vtcam_create(acl->sw, lookup, keymask, &new_vtcam_id, + PRESTERA_HW_VTCAM_DIR_INGRESS); + if (err) { + kfree(vtcam); + return err; + } + + vtcam->id = new_vtcam_id; + vtcam->lookup = lookup; + if (keymask) { + memcpy(vtcam->keymask, keymask, sizeof(vtcam->keymask)); + vtcam->is_keymask_set = true; + } + refcount_set(&vtcam->refcount, 1); + list_add_rcu(&vtcam->list, &acl->vtcam_list); + +vtcam_found: + *vtcam_id = vtcam->id; + return 0; } -int prestera_acl_rule_get_stats(struct prestera_switch *sw, - struct prestera_acl_rule *rule, - u64 *packets, u64 *bytes, u64 *last_use) +int prestera_acl_vtcam_id_put(struct prestera_acl *acl, u32 vtcam_id) { - u64 current_packets; - u64 current_bytes; + struct prestera_acl_vtcam *vtcam; int err; - err = prestera_hw_acl_rule_stats_get(sw, rule->id, ¤t_packets, - ¤t_bytes); - if (err) - return err; + list_for_each_entry(vtcam, &acl->vtcam_list, list) { + if (vtcam_id != vtcam->id) + continue; - *packets = current_packets; - *bytes = current_bytes; - *last_use = jiffies; + if (!refcount_dec_and_test(&vtcam->refcount)) + return 0; - return 0; + err = prestera_hw_vtcam_destroy(acl->sw, vtcam->id); + if (err && err != -ENODEV) { + refcount_set(&vtcam->refcount, 1); + return err; + } + + list_del(&vtcam->list); + kfree(vtcam); + return 0; + } + + return -ENOENT; } int prestera_acl_init(struct prestera_switch *sw) { struct prestera_acl *acl; + int err; acl = kzalloc(sizeof(*acl), GFP_KERNEL); if (!acl) return -ENOMEM; + acl->sw = sw; INIT_LIST_HEAD(&acl->rules); + INIT_LIST_HEAD(&acl->vtcam_list); + idr_init(&acl->uid); + + err = rhashtable_init(&acl->acl_rule_entry_ht, + &__prestera_acl_rule_entry_ht_params); + if (err) + goto err_acl_rule_entry_ht_init; + + err = rhashtable_init(&acl->ruleset_ht, + &prestera_acl_ruleset_ht_params); + if (err) + goto err_ruleset_ht_init; + sw->acl = acl; - acl->sw = sw; return 0; + +err_ruleset_ht_init: + rhashtable_destroy(&acl->acl_rule_entry_ht); +err_acl_rule_entry_ht_init: + kfree(acl); + return err; } void prestera_acl_fini(struct prestera_switch *sw) { struct prestera_acl *acl = sw->acl; + WARN_ON(!idr_is_empty(&acl->uid)); + idr_destroy(&acl->uid); + + WARN_ON(!list_empty(&acl->vtcam_list)); WARN_ON(!list_empty(&acl->rules)); + + rhashtable_destroy(&acl->ruleset_ht); + rhashtable_destroy(&acl->acl_rule_entry_ht); + kfree(acl); } diff --git a/drivers/net/ethernet/marvell/prestera/prestera_acl.h b/drivers/net/ethernet/marvell/prestera/prestera_acl.h index 39b7869be659..b7f9a7904508 100644 --- a/drivers/net/ethernet/marvell/prestera/prestera_acl.h +++ b/drivers/net/ethernet/marvell/prestera/prestera_acl.h @@ -1,114 +1,118 @@ /* SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0 */ -/* Copyright (c) 2020 Marvell International Ltd. All rights reserved. */ +/* Copyright (c) 2020-2021 Marvell International Ltd. All rights reserved. */ #ifndef _PRESTERA_ACL_H_ #define _PRESTERA_ACL_H_ -enum prestera_acl_rule_match_entry_type { - PRESTERA_ACL_RULE_MATCH_ENTRY_TYPE_ETH_TYPE = 1, - PRESTERA_ACL_RULE_MATCH_ENTRY_TYPE_ETH_DMAC, - PRESTERA_ACL_RULE_MATCH_ENTRY_TYPE_ETH_SMAC, - PRESTERA_ACL_RULE_MATCH_ENTRY_TYPE_IP_PROTO, - PRESTERA_ACL_RULE_MATCH_ENTRY_TYPE_PORT, - PRESTERA_ACL_RULE_MATCH_ENTRY_TYPE_IP_SRC, - PRESTERA_ACL_RULE_MATCH_ENTRY_TYPE_IP_DST, - PRESTERA_ACL_RULE_MATCH_ENTRY_TYPE_L4_PORT_SRC, - PRESTERA_ACL_RULE_MATCH_ENTRY_TYPE_L4_PORT_DST, - PRESTERA_ACL_RULE_MATCH_ENTRY_TYPE_L4_PORT_RANGE_SRC, - PRESTERA_ACL_RULE_MATCH_ENTRY_TYPE_L4_PORT_RANGE_DST, - PRESTERA_ACL_RULE_MATCH_ENTRY_TYPE_VLAN_ID, - PRESTERA_ACL_RULE_MATCH_ENTRY_TYPE_VLAN_TPID, - PRESTERA_ACL_RULE_MATCH_ENTRY_TYPE_ICMP_TYPE, - PRESTERA_ACL_RULE_MATCH_ENTRY_TYPE_ICMP_CODE +#include + +#define PRESTERA_ACL_KEYMASK_PCL_ID 0x3FF +#define PRESTERA_ACL_KEYMASK_PCL_ID_USER \ + (PRESTERA_ACL_KEYMASK_PCL_ID & 0x00FF) + +#define rule_match_set_n(match_p, type, val_p, size) \ + memcpy(&(match_p)[PRESTERA_ACL_RULE_MATCH_TYPE_##type], \ + val_p, size) +#define rule_match_set(match_p, type, val) \ + memcpy(&(match_p)[PRESTERA_ACL_RULE_MATCH_TYPE_##type], \ + &(val), sizeof(val)) + +enum prestera_acl_match_type { + PRESTERA_ACL_RULE_MATCH_TYPE_PCL_ID, + PRESTERA_ACL_RULE_MATCH_TYPE_ETH_TYPE, + PRESTERA_ACL_RULE_MATCH_TYPE_ETH_DMAC_0, + PRESTERA_ACL_RULE_MATCH_TYPE_ETH_DMAC_1, + PRESTERA_ACL_RULE_MATCH_TYPE_ETH_SMAC_0, + PRESTERA_ACL_RULE_MATCH_TYPE_ETH_SMAC_1, + PRESTERA_ACL_RULE_MATCH_TYPE_IP_PROTO, + PRESTERA_ACL_RULE_MATCH_TYPE_SYS_PORT, + PRESTERA_ACL_RULE_MATCH_TYPE_SYS_DEV, + PRESTERA_ACL_RULE_MATCH_TYPE_IP_SRC, + PRESTERA_ACL_RULE_MATCH_TYPE_IP_DST, + PRESTERA_ACL_RULE_MATCH_TYPE_L4_PORT_SRC, + PRESTERA_ACL_RULE_MATCH_TYPE_L4_PORT_DST, + PRESTERA_ACL_RULE_MATCH_TYPE_L4_PORT_RANGE_SRC, + PRESTERA_ACL_RULE_MATCH_TYPE_L4_PORT_RANGE_DST, + PRESTERA_ACL_RULE_MATCH_TYPE_VLAN_ID, + PRESTERA_ACL_RULE_MATCH_TYPE_VLAN_TPID, + PRESTERA_ACL_RULE_MATCH_TYPE_ICMP_TYPE, + PRESTERA_ACL_RULE_MATCH_TYPE_ICMP_CODE, + + __PRESTERA_ACL_RULE_MATCH_TYPE_MAX }; enum prestera_acl_rule_action { - PRESTERA_ACL_RULE_ACTION_ACCEPT, - PRESTERA_ACL_RULE_ACTION_DROP, - PRESTERA_ACL_RULE_ACTION_TRAP + PRESTERA_ACL_RULE_ACTION_ACCEPT = 0, + PRESTERA_ACL_RULE_ACTION_DROP = 1, + PRESTERA_ACL_RULE_ACTION_TRAP = 2, + PRESTERA_ACL_RULE_ACTION_COUNT = 7, + + PRESTERA_ACL_RULE_ACTION_MAX }; -struct prestera_switch; -struct prestera_port; -struct prestera_acl_rule; -struct prestera_acl_ruleset; +enum { + PRESTERA_ACL_IFACE_TYPE_PORT, + PRESTERA_ACL_IFACE_TYPE_INDEX +}; -struct prestera_flow_block_binding { - struct list_head list; - struct prestera_port *port; - int span_id; +struct prestera_acl_match { + __be32 key[__PRESTERA_ACL_RULE_MATCH_TYPE_MAX]; + __be32 mask[__PRESTERA_ACL_RULE_MATCH_TYPE_MAX]; }; -struct prestera_flow_block { - struct list_head binding_list; - struct prestera_switch *sw; - struct net *net; - struct prestera_acl_ruleset *ruleset; - struct flow_block_cb *block_cb; +struct prestera_acl_rule_entry_key { + u32 prio; + struct prestera_acl_match match; }; -struct prestera_acl_rule_action_entry { - struct list_head list; +struct prestera_acl_hw_action_info { enum prestera_acl_rule_action id; }; -struct prestera_acl_rule_match_entry { +/* This struct (arg) used only to be passed as parameter for + * acl_rule_entry_create. Must be flat. Can contain object keys, which will be + * resolved to object links, before saving to acl_rule_entry struct + */ +struct prestera_acl_rule_entry_arg { + u32 vtcam_id; + struct { + struct { + u8 valid:1; + } accept, drop, trap; + }; +}; + +struct prestera_acl_rule { + struct rhash_head ht_node; /* Member of acl HT */ struct list_head list; - enum prestera_acl_rule_match_entry_type type; + struct prestera_acl_ruleset *ruleset; + unsigned long cookie; + u32 priority; + struct prestera_acl_rule_entry_key re_key; + struct prestera_acl_rule_entry_arg re_arg; + struct prestera_acl_rule_entry *re; +}; + +struct prestera_acl_iface { + u8 type; union { - struct { - u8 key; - u8 mask; - } u8; - struct { - u16 key; - u16 mask; - } u16; - struct { - u32 key; - u32 mask; - } u32; - struct { - u64 key; - u64 mask; - } u64; - struct { - u8 key[ETH_ALEN]; - u8 mask[ETH_ALEN]; - } mac; - } keymask; + struct prestera_port *port; + u32 index; + }; }; +struct prestera_acl; +struct prestera_switch; +struct prestera_flow_block; + int prestera_acl_init(struct prestera_switch *sw); void prestera_acl_fini(struct prestera_switch *sw); -struct prestera_flow_block * -prestera_acl_block_create(struct prestera_switch *sw, struct net *net); -void prestera_acl_block_destroy(struct prestera_flow_block *block); -struct net *prestera_acl_block_net(struct prestera_flow_block *block); -struct prestera_switch *prestera_acl_block_sw(struct prestera_flow_block *block); -int prestera_acl_block_bind(struct prestera_flow_block *block, - struct prestera_port *port); -int prestera_acl_block_unbind(struct prestera_flow_block *block, - struct prestera_port *port); -struct prestera_acl_ruleset * -prestera_acl_block_ruleset_get(struct prestera_flow_block *block); + struct prestera_acl_rule * -prestera_acl_rule_create(struct prestera_flow_block *block, +prestera_acl_rule_create(struct prestera_acl_ruleset *ruleset, unsigned long cookie); -u32 prestera_acl_rule_priority_get(struct prestera_acl_rule *rule); void prestera_acl_rule_priority_set(struct prestera_acl_rule *rule, u32 priority); -u16 prestera_acl_rule_ruleset_id_get(const struct prestera_acl_rule *rule); -struct list_head * -prestera_acl_rule_action_list_get(struct prestera_acl_rule *rule); -u8 prestera_acl_rule_action_len(struct prestera_acl_rule *rule); -u8 prestera_acl_rule_match_len(struct prestera_acl_rule *rule); -int prestera_acl_rule_action_add(struct prestera_acl_rule *rule, - struct prestera_acl_rule_action_entry *entry); -struct list_head * -prestera_acl_rule_match_list_get(struct prestera_acl_rule *rule); -int prestera_acl_rule_match_add(struct prestera_acl_rule *rule, - struct prestera_acl_rule_match_entry *entry); void prestera_acl_rule_destroy(struct prestera_acl_rule *rule); struct prestera_acl_rule * prestera_acl_rule_lookup(struct prestera_acl_ruleset *ruleset, @@ -117,8 +121,39 @@ int prestera_acl_rule_add(struct prestera_switch *sw, struct prestera_acl_rule *rule); void prestera_acl_rule_del(struct prestera_switch *sw, struct prestera_acl_rule *rule); -int prestera_acl_rule_get_stats(struct prestera_switch *sw, +int prestera_acl_rule_get_stats(struct prestera_acl *acl, struct prestera_acl_rule *rule, u64 *packets, u64 *bytes, u64 *last_use); +struct prestera_acl_rule_entry * +prestera_acl_rule_entry_find(struct prestera_acl *acl, + struct prestera_acl_rule_entry_key *key); +void prestera_acl_rule_entry_destroy(struct prestera_acl *acl, + struct prestera_acl_rule_entry *e); +struct prestera_acl_rule_entry * +prestera_acl_rule_entry_create(struct prestera_acl *acl, + struct prestera_acl_rule_entry_key *key, + struct prestera_acl_rule_entry_arg *arg); +struct prestera_acl_ruleset * +prestera_acl_ruleset_get(struct prestera_acl *acl, + struct prestera_flow_block *block); +struct prestera_acl_ruleset * +prestera_acl_ruleset_lookup(struct prestera_acl *acl, + struct prestera_flow_block *block); +bool prestera_acl_ruleset_is_offload(struct prestera_acl_ruleset *ruleset); +int prestera_acl_ruleset_keymask_set(struct prestera_acl_ruleset *ruleset, + void *keymask); +int prestera_acl_ruleset_offload(struct prestera_acl_ruleset *ruleset); +void prestera_acl_ruleset_put(struct prestera_acl_ruleset *ruleset); +int prestera_acl_ruleset_bind(struct prestera_acl_ruleset *ruleset, + struct prestera_port *port); +int prestera_acl_ruleset_unbind(struct prestera_acl_ruleset *ruleset, + struct prestera_port *port); +void +prestera_acl_rule_keymask_pcl_id_set(struct prestera_acl_rule *rule, + u16 pcl_id); + +int prestera_acl_vtcam_id_get(struct prestera_acl *acl, u8 lookup, + void *keymask, u32 *vtcam_id); +int prestera_acl_vtcam_id_put(struct prestera_acl *acl, u32 vtcam_id); #endif /* _PRESTERA_ACL_H_ */ diff --git a/drivers/net/ethernet/marvell/prestera/prestera_flow.c b/drivers/net/ethernet/marvell/prestera/prestera_flow.c index c9891e968259..8e52bf6edb83 100644 --- a/drivers/net/ethernet/marvell/prestera/prestera_flow.c +++ b/drivers/net/ethernet/marvell/prestera/prestera_flow.c @@ -29,17 +29,19 @@ static int prestera_flow_block_mall_cb(struct prestera_flow_block *block, static int prestera_flow_block_flower_cb(struct prestera_flow_block *block, struct flow_cls_offload *f) { + struct prestera_switch *sw = block->sw; + if (f->common.chain_index != 0) return -EOPNOTSUPP; switch (f->command) { case FLOW_CLS_REPLACE: - return prestera_flower_replace(block, f); + return prestera_flower_replace(sw, block, f); case FLOW_CLS_DESTROY: - prestera_flower_destroy(block, f); + prestera_flower_destroy(sw, block, f); return 0; case FLOW_CLS_STATS: - return prestera_flower_stats(block, f); + return prestera_flower_stats(sw, block, f); default: return -EOPNOTSUPP; } @@ -60,11 +62,100 @@ static int prestera_flow_block_cb(enum tc_setup_type type, } } +static void prestera_flow_block_destroy(void *cb_priv) +{ + struct prestera_flow_block *block = cb_priv; + + WARN_ON(!list_empty(&block->binding_list)); + + kfree(block); +} + +static struct prestera_flow_block * +prestera_flow_block_create(struct prestera_switch *sw, struct net *net) +{ + struct prestera_flow_block *block; + + block = kzalloc(sizeof(*block), GFP_KERNEL); + if (!block) + return NULL; + + INIT_LIST_HEAD(&block->binding_list); + block->net = net; + block->sw = sw; + + return block; +} + static void prestera_flow_block_release(void *cb_priv) { struct prestera_flow_block *block = cb_priv; - prestera_acl_block_destroy(block); + prestera_flow_block_destroy(block); +} + +static inline bool +prestera_flow_block_is_bound(const struct prestera_flow_block *block) +{ + return block->ruleset_zero; +} + +static struct prestera_flow_block_binding * +prestera_flow_block_lookup(struct prestera_flow_block *block, + struct prestera_port *port) +{ + struct prestera_flow_block_binding *binding; + + list_for_each_entry(binding, &block->binding_list, list) + if (binding->port == port) + return binding; + + return NULL; +} + +static int prestera_flow_block_bind(struct prestera_flow_block *block, + struct prestera_port *port) +{ + struct prestera_flow_block_binding *binding; + int err; + + binding = kzalloc(sizeof(*binding), GFP_KERNEL); + if (!binding) + return -ENOMEM; + + binding->span_id = PRESTERA_SPAN_INVALID_ID; + binding->port = port; + + if (prestera_flow_block_is_bound(block)) { + err = prestera_acl_ruleset_bind(block->ruleset_zero, port); + if (err) + goto err_ruleset_bind; + } + + list_add(&binding->list, &block->binding_list); + return 0; + +err_ruleset_bind: + kfree(binding); + return err; +} + +static int prestera_flow_block_unbind(struct prestera_flow_block *block, + struct prestera_port *port) +{ + struct prestera_flow_block_binding *binding; + + binding = prestera_flow_block_lookup(block, port); + if (!binding) + return -ENOENT; + + list_del(&binding->list); + + if (prestera_flow_block_is_bound(block)) + prestera_acl_ruleset_unbind(block->ruleset_zero, port); + + kfree(binding); + return 0; } static struct prestera_flow_block * @@ -78,7 +169,7 @@ prestera_flow_block_get(struct prestera_switch *sw, block_cb = flow_block_cb_lookup(f->block, prestera_flow_block_cb, sw); if (!block_cb) { - block = prestera_acl_block_create(sw, f->net); + block = prestera_flow_block_create(sw, f->net); if (!block) return ERR_PTR(-ENOMEM); @@ -86,7 +177,7 @@ prestera_flow_block_get(struct prestera_switch *sw, sw, block, prestera_flow_block_release); if (IS_ERR(block_cb)) { - prestera_acl_block_destroy(block); + prestera_flow_block_destroy(block); return ERR_CAST(block_cb); } @@ -110,7 +201,7 @@ static void prestera_flow_block_put(struct prestera_flow_block *block) return; flow_block_cb_free(block_cb); - prestera_acl_block_destroy(block); + prestera_flow_block_destroy(block); } static int prestera_setup_flow_block_bind(struct prestera_port *port, @@ -128,7 +219,7 @@ static int prestera_setup_flow_block_bind(struct prestera_port *port, block_cb = block->block_cb; - err = prestera_acl_block_bind(block, port); + err = prestera_flow_block_bind(block, port); if (err) goto err_block_bind; @@ -162,7 +253,7 @@ static void prestera_setup_flow_block_unbind(struct prestera_port *port, prestera_span_destroy(block); - err = prestera_acl_block_unbind(block, port); + err = prestera_flow_block_unbind(block, port); if (err) goto error; diff --git a/drivers/net/ethernet/marvell/prestera/prestera_flow.h b/drivers/net/ethernet/marvell/prestera/prestera_flow.h index 467c7038cace..5863acf06005 100644 --- a/drivers/net/ethernet/marvell/prestera/prestera_flow.h +++ b/drivers/net/ethernet/marvell/prestera/prestera_flow.h @@ -7,6 +7,22 @@ #include struct prestera_port; +struct prestera_switch; + +struct prestera_flow_block_binding { + struct list_head list; + struct prestera_port *port; + int span_id; +}; + +struct prestera_flow_block { + struct list_head binding_list; + struct prestera_switch *sw; + unsigned int rule_count; + struct net *net; + struct prestera_acl_ruleset *ruleset_zero; + struct flow_block_cb *block_cb; +}; int prestera_flow_block_setup(struct prestera_port *port, struct flow_block_offload *f); diff --git a/drivers/net/ethernet/marvell/prestera/prestera_flower.c b/drivers/net/ethernet/marvell/prestera/prestera_flower.c index e571ba09ec08..a52dd564c41c 100644 --- a/drivers/net/ethernet/marvell/prestera/prestera_flower.c +++ b/drivers/net/ethernet/marvell/prestera/prestera_flower.c @@ -3,6 +3,7 @@ #include "prestera.h" #include "prestera_acl.h" +#include "prestera_flow.h" #include "prestera_flower.h" static int prestera_flower_parse_actions(struct prestera_flow_block *block, @@ -10,35 +11,38 @@ static int prestera_flower_parse_actions(struct prestera_flow_block *block, struct flow_action *flow_action, struct netlink_ext_ack *extack) { - struct prestera_acl_rule_action_entry a_entry; const struct flow_action_entry *act; - int err, i; + int i; + /* whole struct (rule->re_arg) must be initialized with 0 */ if (!flow_action_has_entries(flow_action)) return 0; flow_action_for_each(i, act, flow_action) { - memset(&a_entry, 0, sizeof(a_entry)); - switch (act->id) { case FLOW_ACTION_ACCEPT: - a_entry.id = PRESTERA_ACL_RULE_ACTION_ACCEPT; + if (rule->re_arg.accept.valid) + return -EEXIST; + + rule->re_arg.accept.valid = 1; break; case FLOW_ACTION_DROP: - a_entry.id = PRESTERA_ACL_RULE_ACTION_DROP; + if (rule->re_arg.drop.valid) + return -EEXIST; + + rule->re_arg.drop.valid = 1; break; case FLOW_ACTION_TRAP: - a_entry.id = PRESTERA_ACL_RULE_ACTION_TRAP; + if (rule->re_arg.trap.valid) + return -EEXIST; + + rule->re_arg.trap.valid = 1; break; default: NL_SET_ERR_MSG_MOD(extack, "Unsupported action"); pr_err("Unsupported action\n"); return -EOPNOTSUPP; } - - err = prestera_acl_rule_action_add(rule, &a_entry); - if (err) - return err; } return 0; @@ -47,12 +51,12 @@ static int prestera_flower_parse_actions(struct prestera_flow_block *block, static int prestera_flower_parse_meta(struct prestera_acl_rule *rule, struct flow_cls_offload *f, struct prestera_flow_block *block) -{ - struct flow_rule *f_rule = flow_cls_offload_flow_rule(f); - struct prestera_acl_rule_match_entry m_entry = {0}; +{ struct flow_rule *f_rule = flow_cls_offload_flow_rule(f); + struct prestera_acl_match *r_match = &rule->re_key.match; + struct prestera_port *port; struct net_device *ingress_dev; struct flow_match_meta match; - struct prestera_port *port; + __be16 key, mask; flow_rule_match_meta(f_rule, &match); if (match.mask->ingress_ifindex != 0xFFFFFFFF) { @@ -61,7 +65,7 @@ static int prestera_flower_parse_meta(struct prestera_acl_rule *rule, return -EINVAL; } - ingress_dev = __dev_get_by_index(prestera_acl_block_net(block), + ingress_dev = __dev_get_by_index(block->net, match.key->ingress_ifindex); if (!ingress_dev) { NL_SET_ERR_MSG_MOD(f->common.extack, @@ -76,22 +80,28 @@ static int prestera_flower_parse_meta(struct prestera_acl_rule *rule, } port = netdev_priv(ingress_dev); - m_entry.type = PRESTERA_ACL_RULE_MATCH_ENTRY_TYPE_PORT; - m_entry.keymask.u64.key = port->hw_id | ((u64)port->dev_id << 32); - m_entry.keymask.u64.mask = ~(u64)0; + mask = htons(0x1FFF); + key = htons(port->hw_id); + rule_match_set(r_match->key, SYS_PORT, key); + rule_match_set(r_match->mask, SYS_PORT, mask); + + mask = htons(0x1FF); + key = htons(port->dev_id); + rule_match_set(r_match->key, SYS_DEV, key); + rule_match_set(r_match->mask, SYS_DEV, mask); + + return 0; - return prestera_acl_rule_match_add(rule, &m_entry); } static int prestera_flower_parse(struct prestera_flow_block *block, struct prestera_acl_rule *rule, struct flow_cls_offload *f) -{ - struct flow_rule *f_rule = flow_cls_offload_flow_rule(f); +{ struct flow_rule *f_rule = flow_cls_offload_flow_rule(f); struct flow_dissector *dissector = f_rule->match.dissector; - struct prestera_acl_rule_match_entry m_entry; - u16 n_proto_mask = 0; - u16 n_proto_key = 0; + struct prestera_acl_match *r_match = &rule->re_key.match; + __be16 n_proto_mask = 0; + __be16 n_proto_key = 0; u16 addr_type = 0; u8 ip_proto = 0; int err; @@ -129,32 +139,19 @@ static int prestera_flower_parse(struct prestera_flow_block *block, struct flow_match_basic match; flow_rule_match_basic(f_rule, &match); - n_proto_key = ntohs(match.key->n_proto); - n_proto_mask = ntohs(match.mask->n_proto); + n_proto_key = match.key->n_proto; + n_proto_mask = match.mask->n_proto; - if (n_proto_key == ETH_P_ALL) { + if (ntohs(match.key->n_proto) == ETH_P_ALL) { n_proto_key = 0; n_proto_mask = 0; } - /* add eth type key,mask */ - memset(&m_entry, 0, sizeof(m_entry)); - m_entry.type = PRESTERA_ACL_RULE_MATCH_ENTRY_TYPE_ETH_TYPE; - m_entry.keymask.u16.key = n_proto_key; - m_entry.keymask.u16.mask = n_proto_mask; - err = prestera_acl_rule_match_add(rule, &m_entry); - if (err) - return err; - - /* add ip proto key,mask */ - memset(&m_entry, 0, sizeof(m_entry)); - m_entry.type = PRESTERA_ACL_RULE_MATCH_ENTRY_TYPE_IP_PROTO; - m_entry.keymask.u8.key = match.key->ip_proto; - m_entry.keymask.u8.mask = match.mask->ip_proto; - err = prestera_acl_rule_match_add(rule, &m_entry); - if (err) - return err; + rule_match_set(r_match->key, ETH_TYPE, n_proto_key); + rule_match_set(r_match->mask, ETH_TYPE, n_proto_mask); + rule_match_set(r_match->key, IP_PROTO, match.key->ip_proto); + rule_match_set(r_match->mask, IP_PROTO, match.mask->ip_proto); ip_proto = match.key->ip_proto; } @@ -163,27 +160,27 @@ static int prestera_flower_parse(struct prestera_flow_block *block, flow_rule_match_eth_addrs(f_rule, &match); - /* add ethernet dst key,mask */ - memset(&m_entry, 0, sizeof(m_entry)); - m_entry.type = PRESTERA_ACL_RULE_MATCH_ENTRY_TYPE_ETH_DMAC; - memcpy(&m_entry.keymask.mac.key, - &match.key->dst, sizeof(match.key->dst)); - memcpy(&m_entry.keymask.mac.mask, - &match.mask->dst, sizeof(match.mask->dst)); - err = prestera_acl_rule_match_add(rule, &m_entry); - if (err) - return err; - - /* add ethernet src key,mask */ - memset(&m_entry, 0, sizeof(m_entry)); - m_entry.type = PRESTERA_ACL_RULE_MATCH_ENTRY_TYPE_ETH_SMAC; - memcpy(&m_entry.keymask.mac.key, - &match.key->src, sizeof(match.key->src)); - memcpy(&m_entry.keymask.mac.mask, - &match.mask->src, sizeof(match.mask->src)); - err = prestera_acl_rule_match_add(rule, &m_entry); - if (err) - return err; + /* DA key, mask */ + rule_match_set_n(r_match->key, + ETH_DMAC_0, &match.key->dst[0], 4); + rule_match_set_n(r_match->key, + ETH_DMAC_1, &match.key->dst[4], 2); + + rule_match_set_n(r_match->mask, + ETH_DMAC_0, &match.mask->dst[0], 4); + rule_match_set_n(r_match->mask, + ETH_DMAC_1, &match.mask->dst[4], 2); + + /* SA key, mask */ + rule_match_set_n(r_match->key, + ETH_SMAC_0, &match.key->src[0], 4); + rule_match_set_n(r_match->key, + ETH_SMAC_1, &match.key->src[4], 2); + + rule_match_set_n(r_match->mask, + ETH_SMAC_0, &match.mask->src[0], 4); + rule_match_set_n(r_match->mask, + ETH_SMAC_1, &match.mask->src[4], 2); } if (addr_type == FLOW_DISSECTOR_KEY_IPV4_ADDRS) { @@ -191,25 +188,11 @@ static int prestera_flower_parse(struct prestera_flow_block *block, flow_rule_match_ipv4_addrs(f_rule, &match); - memset(&m_entry, 0, sizeof(m_entry)); - m_entry.type = PRESTERA_ACL_RULE_MATCH_ENTRY_TYPE_IP_SRC; - memcpy(&m_entry.keymask.u32.key, - &match.key->src, sizeof(match.key->src)); - memcpy(&m_entry.keymask.u32.mask, - &match.mask->src, sizeof(match.mask->src)); - err = prestera_acl_rule_match_add(rule, &m_entry); - if (err) - return err; + rule_match_set(r_match->key, IP_SRC, match.key->src); + rule_match_set(r_match->mask, IP_SRC, match.mask->src); - memset(&m_entry, 0, sizeof(m_entry)); - m_entry.type = PRESTERA_ACL_RULE_MATCH_ENTRY_TYPE_IP_DST; - memcpy(&m_entry.keymask.u32.key, - &match.key->dst, sizeof(match.key->dst)); - memcpy(&m_entry.keymask.u32.mask, - &match.mask->dst, sizeof(match.mask->dst)); - err = prestera_acl_rule_match_add(rule, &m_entry); - if (err) - return err; + rule_match_set(r_match->key, IP_DST, match.key->dst); + rule_match_set(r_match->mask, IP_DST, match.mask->dst); } if (flow_rule_match_key(f_rule, FLOW_DISSECTOR_KEY_PORTS)) { @@ -224,21 +207,11 @@ static int prestera_flower_parse(struct prestera_flow_block *block, flow_rule_match_ports(f_rule, &match); - memset(&m_entry, 0, sizeof(m_entry)); - m_entry.type = PRESTERA_ACL_RULE_MATCH_ENTRY_TYPE_L4_PORT_SRC; - m_entry.keymask.u16.key = ntohs(match.key->src); - m_entry.keymask.u16.mask = ntohs(match.mask->src); - err = prestera_acl_rule_match_add(rule, &m_entry); - if (err) - return err; + rule_match_set(r_match->key, L4_PORT_SRC, match.key->src); + rule_match_set(r_match->mask, L4_PORT_SRC, match.mask->src); - memset(&m_entry, 0, sizeof(m_entry)); - m_entry.type = PRESTERA_ACL_RULE_MATCH_ENTRY_TYPE_L4_PORT_DST; - m_entry.keymask.u16.key = ntohs(match.key->dst); - m_entry.keymask.u16.mask = ntohs(match.mask->dst); - err = prestera_acl_rule_match_add(rule, &m_entry); - if (err) - return err; + rule_match_set(r_match->key, L4_PORT_DST, match.key->dst); + rule_match_set(r_match->mask, L4_PORT_DST, match.mask->dst); } if (flow_rule_match_key(f_rule, FLOW_DISSECTOR_KEY_VLAN)) { @@ -247,22 +220,15 @@ static int prestera_flower_parse(struct prestera_flow_block *block, flow_rule_match_vlan(f_rule, &match); if (match.mask->vlan_id != 0) { - memset(&m_entry, 0, sizeof(m_entry)); - m_entry.type = PRESTERA_ACL_RULE_MATCH_ENTRY_TYPE_VLAN_ID; - m_entry.keymask.u16.key = match.key->vlan_id; - m_entry.keymask.u16.mask = match.mask->vlan_id; - err = prestera_acl_rule_match_add(rule, &m_entry); - if (err) - return err; + __be16 key = cpu_to_be16(match.key->vlan_id); + __be16 mask = cpu_to_be16(match.mask->vlan_id); + + rule_match_set(r_match->key, VLAN_ID, key); + rule_match_set(r_match->mask, VLAN_ID, mask); } - memset(&m_entry, 0, sizeof(m_entry)); - m_entry.type = PRESTERA_ACL_RULE_MATCH_ENTRY_TYPE_VLAN_TPID; - m_entry.keymask.u16.key = ntohs(match.key->vlan_tpid); - m_entry.keymask.u16.mask = ntohs(match.mask->vlan_tpid); - err = prestera_acl_rule_match_add(rule, &m_entry); - if (err) - return err; + rule_match_set(r_match->key, VLAN_TPID, match.key->vlan_tpid); + rule_match_set(r_match->mask, VLAN_TPID, match.mask->vlan_tpid); } if (flow_rule_match_key(f_rule, FLOW_DISSECTOR_KEY_ICMP)) { @@ -270,90 +236,112 @@ static int prestera_flower_parse(struct prestera_flow_block *block, flow_rule_match_icmp(f_rule, &match); - memset(&m_entry, 0, sizeof(m_entry)); - m_entry.type = PRESTERA_ACL_RULE_MATCH_ENTRY_TYPE_ICMP_TYPE; - m_entry.keymask.u8.key = match.key->type; - m_entry.keymask.u8.mask = match.mask->type; - err = prestera_acl_rule_match_add(rule, &m_entry); - if (err) - return err; + rule_match_set(r_match->key, ICMP_TYPE, match.key->type); + rule_match_set(r_match->mask, ICMP_TYPE, match.mask->type); - memset(&m_entry, 0, sizeof(m_entry)); - m_entry.type = PRESTERA_ACL_RULE_MATCH_ENTRY_TYPE_ICMP_CODE; - m_entry.keymask.u8.key = match.key->code; - m_entry.keymask.u8.mask = match.mask->code; - err = prestera_acl_rule_match_add(rule, &m_entry); - if (err) - return err; + rule_match_set(r_match->key, ICMP_CODE, match.key->code); + rule_match_set(r_match->mask, ICMP_CODE, match.mask->code); } - return prestera_flower_parse_actions(block, rule, - &f->rule->action, + return prestera_flower_parse_actions(block, rule, &f->rule->action, f->common.extack); } -int prestera_flower_replace(struct prestera_flow_block *block, +int prestera_flower_replace(struct prestera_switch *sw, + struct prestera_flow_block *block, struct flow_cls_offload *f) { - struct prestera_switch *sw = prestera_acl_block_sw(block); + struct prestera_acl_ruleset *ruleset; + struct prestera_acl *acl = sw->acl; struct prestera_acl_rule *rule; int err; - rule = prestera_acl_rule_create(block, f->cookie); - if (IS_ERR(rule)) - return PTR_ERR(rule); + ruleset = prestera_acl_ruleset_get(acl, block); + if (IS_ERR(ruleset)) + return PTR_ERR(ruleset); + + /* increments the ruleset reference */ + rule = prestera_acl_rule_create(ruleset, f->cookie); + if (IS_ERR(rule)) { + err = PTR_ERR(rule); + goto err_rule_create; + } err = prestera_flower_parse(block, rule, f); if (err) - goto err_flower_parse; + goto err_rule_add; + + if (!prestera_acl_ruleset_is_offload(ruleset)) { + err = prestera_acl_ruleset_offload(ruleset); + if (err) + goto err_ruleset_offload; + } err = prestera_acl_rule_add(sw, rule); if (err) goto err_rule_add; + prestera_acl_ruleset_put(ruleset); return 0; +err_ruleset_offload: err_rule_add: -err_flower_parse: prestera_acl_rule_destroy(rule); +err_rule_create: + prestera_acl_ruleset_put(ruleset); return err; } -void prestera_flower_destroy(struct prestera_flow_block *block, +void prestera_flower_destroy(struct prestera_switch *sw, + struct prestera_flow_block *block, struct flow_cls_offload *f) { + struct prestera_acl_ruleset *ruleset; struct prestera_acl_rule *rule; - struct prestera_switch *sw; - rule = prestera_acl_rule_lookup(prestera_acl_block_ruleset_get(block), - f->cookie); + ruleset = prestera_acl_ruleset_lookup(sw->acl, block); + if (IS_ERR(ruleset)) + return; + + rule = prestera_acl_rule_lookup(ruleset, f->cookie); if (rule) { - sw = prestera_acl_block_sw(block); prestera_acl_rule_del(sw, rule); prestera_acl_rule_destroy(rule); } + prestera_acl_ruleset_put(ruleset); + } -int prestera_flower_stats(struct prestera_flow_block *block, +int prestera_flower_stats(struct prestera_switch *sw, + struct prestera_flow_block *block, struct flow_cls_offload *f) { - struct prestera_switch *sw = prestera_acl_block_sw(block); + struct prestera_acl_ruleset *ruleset; struct prestera_acl_rule *rule; u64 packets; u64 lastuse; u64 bytes; int err; - rule = prestera_acl_rule_lookup(prestera_acl_block_ruleset_get(block), - f->cookie); - if (!rule) - return -EINVAL; + ruleset = prestera_acl_ruleset_lookup(sw->acl, block); + if (IS_ERR(ruleset)) + return PTR_ERR(ruleset); + + rule = prestera_acl_rule_lookup(ruleset, f->cookie); + if (!rule) { + err = -EINVAL; + goto err_rule_get_stats; + } - err = prestera_acl_rule_get_stats(sw, rule, &packets, &bytes, &lastuse); + err = prestera_acl_rule_get_stats(sw->acl, rule, &packets, + &bytes, &lastuse); if (err) - return err; + goto err_rule_get_stats; flow_stats_update(&f->stats, bytes, packets, 0, lastuse, - FLOW_ACTION_HW_STATS_IMMEDIATE); - return 0; + FLOW_ACTION_HW_STATS_DELAYED); + +err_rule_get_stats: + prestera_acl_ruleset_put(ruleset); + return err; } diff --git a/drivers/net/ethernet/marvell/prestera/prestera_flower.h b/drivers/net/ethernet/marvell/prestera/prestera_flower.h index 91e045eec58b..6e550e36ab99 100644 --- a/drivers/net/ethernet/marvell/prestera/prestera_flower.h +++ b/drivers/net/ethernet/marvell/prestera/prestera_flower.h @@ -1,18 +1,22 @@ /* SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0 */ -/* Copyright (c) 2020 Marvell International Ltd. All rights reserved. */ +/* Copyright (c) 2020-2021 Marvell International Ltd. All rights reserved. */ #ifndef _PRESTERA_FLOWER_H_ #define _PRESTERA_FLOWER_H_ #include +struct prestera_switch; struct prestera_flow_block; -int prestera_flower_replace(struct prestera_flow_block *block, +int prestera_flower_replace(struct prestera_switch *sw, + struct prestera_flow_block *block, struct flow_cls_offload *f); -void prestera_flower_destroy(struct prestera_flow_block *block, +void prestera_flower_destroy(struct prestera_switch *sw, + struct prestera_flow_block *block, struct flow_cls_offload *f); -int prestera_flower_stats(struct prestera_flow_block *block, +int prestera_flower_stats(struct prestera_switch *sw, + struct prestera_flow_block *block, struct flow_cls_offload *f); #endif /* _PRESTERA_FLOWER_H_ */ diff --git a/drivers/net/ethernet/marvell/prestera/prestera_hw.c b/drivers/net/ethernet/marvell/prestera/prestera_hw.c index 9b8b1ed474fc..d6c425b651cb 100644 --- a/drivers/net/ethernet/marvell/prestera/prestera_hw.c +++ b/drivers/net/ethernet/marvell/prestera/prestera_hw.c @@ -38,13 +38,12 @@ enum prestera_cmd_type_t { PRESTERA_CMD_TYPE_BRIDGE_PORT_ADD = 0x402, PRESTERA_CMD_TYPE_BRIDGE_PORT_DELETE = 0x403, - PRESTERA_CMD_TYPE_ACL_RULE_ADD = 0x500, - PRESTERA_CMD_TYPE_ACL_RULE_DELETE = 0x501, - PRESTERA_CMD_TYPE_ACL_RULE_STATS_GET = 0x510, - PRESTERA_CMD_TYPE_ACL_RULESET_CREATE = 0x520, - PRESTERA_CMD_TYPE_ACL_RULESET_DELETE = 0x521, - PRESTERA_CMD_TYPE_ACL_PORT_BIND = 0x530, - PRESTERA_CMD_TYPE_ACL_PORT_UNBIND = 0x531, + PRESTERA_CMD_TYPE_VTCAM_CREATE = 0x540, + PRESTERA_CMD_TYPE_VTCAM_DESTROY = 0x541, + PRESTERA_CMD_TYPE_VTCAM_RULE_ADD = 0x550, + PRESTERA_CMD_TYPE_VTCAM_RULE_DELETE = 0x551, + PRESTERA_CMD_TYPE_VTCAM_IFACE_BIND = 0x560, + PRESTERA_CMD_TYPE_VTCAM_IFACE_UNBIND = 0x561, PRESTERA_CMD_TYPE_RXTX_INIT = 0x800, @@ -359,76 +358,57 @@ struct prestera_msg_bridge_resp { u8 pad[2]; }; -struct prestera_msg_acl_action { - __le32 id; - __le32 reserved[5]; +struct prestera_msg_vtcam_create_req { + struct prestera_msg_cmd cmd; + __le32 keymask[__PRESTERA_ACL_RULE_MATCH_TYPE_MAX]; + u8 direction; + u8 lookup; + u8 pad[2]; }; -struct prestera_msg_acl_match { - __le32 type; - __le32 __reserved; - union { - struct { - u8 key; - u8 mask; - } u8; - struct { - __le16 key; - __le16 mask; - } u16; - struct { - __le32 key; - __le32 mask; - } u32; - struct { - __le64 key; - __le64 mask; - } u64; - struct { - u8 key[ETH_ALEN]; - u8 mask[ETH_ALEN]; - } mac; - } keymask; +struct prestera_msg_vtcam_destroy_req { + struct prestera_msg_cmd cmd; + __le32 vtcam_id; }; -struct prestera_msg_acl_rule_req { +struct prestera_msg_vtcam_rule_add_req { struct prestera_msg_cmd cmd; - __le32 id; - __le32 priority; - __le16 ruleset_id; - u8 n_actions; - u8 n_matches; + __le32 key[__PRESTERA_ACL_RULE_MATCH_TYPE_MAX]; + __le32 keymask[__PRESTERA_ACL_RULE_MATCH_TYPE_MAX]; + __le32 vtcam_id; + __le32 prio; + __le32 n_act; }; -struct prestera_msg_acl_rule_resp { - struct prestera_msg_ret ret; +struct prestera_msg_vtcam_rule_del_req { + struct prestera_msg_cmd cmd; + __le32 vtcam_id; __le32 id; }; -struct prestera_msg_acl_rule_stats_resp { - struct prestera_msg_ret ret; - __le64 packets; - __le64 bytes; -}; - -struct prestera_msg_acl_ruleset_bind_req { +struct prestera_msg_vtcam_bind_req { struct prestera_msg_cmd cmd; - __le32 port; - __le32 dev; - __le16 ruleset_id; - u8 pad[2]; + union { + struct { + __le32 hw_id; + __le32 dev_id; + } port; + __le32 index; + }; + __le32 vtcam_id; + __le16 pcl_id; + __le16 type; }; -struct prestera_msg_acl_ruleset_req { - struct prestera_msg_cmd cmd; - __le16 id; - u8 pad[2]; +struct prestera_msg_vtcam_resp { + struct prestera_msg_ret ret; + __le32 vtcam_id; + __le32 rule_id; }; -struct prestera_msg_acl_ruleset_resp { - struct prestera_msg_ret ret; - __le16 id; - u8 pad[2]; +struct prestera_msg_acl_action { + __le32 id; + __le32 __reserved[7]; }; struct prestera_msg_span_req { @@ -521,14 +501,17 @@ static void prestera_hw_build_tests(void) BUILD_BUG_ON(sizeof(struct prestera_msg_vlan_req) != 16); BUILD_BUG_ON(sizeof(struct prestera_msg_fdb_req) != 28); BUILD_BUG_ON(sizeof(struct prestera_msg_bridge_req) != 16); - BUILD_BUG_ON(sizeof(struct prestera_msg_acl_rule_req) != 16); - BUILD_BUG_ON(sizeof(struct prestera_msg_acl_ruleset_bind_req) != 16); - BUILD_BUG_ON(sizeof(struct prestera_msg_acl_ruleset_req) != 8); BUILD_BUG_ON(sizeof(struct prestera_msg_span_req) != 16); BUILD_BUG_ON(sizeof(struct prestera_msg_stp_req) != 16); BUILD_BUG_ON(sizeof(struct prestera_msg_rxtx_req) != 8); BUILD_BUG_ON(sizeof(struct prestera_msg_lag_req) != 16); BUILD_BUG_ON(sizeof(struct prestera_msg_cpu_code_counter_req) != 8); + BUILD_BUG_ON(sizeof(struct prestera_msg_vtcam_create_req) != 84); + BUILD_BUG_ON(sizeof(struct prestera_msg_vtcam_destroy_req) != 8); + BUILD_BUG_ON(sizeof(struct prestera_msg_vtcam_rule_add_req) != 168); + BUILD_BUG_ON(sizeof(struct prestera_msg_vtcam_rule_del_req) != 12); + BUILD_BUG_ON(sizeof(struct prestera_msg_vtcam_bind_req) != 20); + BUILD_BUG_ON(sizeof(struct prestera_msg_acl_action) != 32); /* check responses */ BUILD_BUG_ON(sizeof(struct prestera_msg_common_resp) != 8); @@ -537,11 +520,9 @@ static void prestera_hw_build_tests(void) BUILD_BUG_ON(sizeof(struct prestera_msg_port_stats_resp) != 248); BUILD_BUG_ON(sizeof(struct prestera_msg_port_info_resp) != 20); BUILD_BUG_ON(sizeof(struct prestera_msg_bridge_resp) != 12); - BUILD_BUG_ON(sizeof(struct prestera_msg_acl_rule_resp) != 12); - BUILD_BUG_ON(sizeof(struct prestera_msg_acl_rule_stats_resp) != 24); - BUILD_BUG_ON(sizeof(struct prestera_msg_acl_ruleset_resp) != 12); BUILD_BUG_ON(sizeof(struct prestera_msg_span_resp) != 12); BUILD_BUG_ON(sizeof(struct prestera_msg_rxtx_resp) != 12); + BUILD_BUG_ON(sizeof(struct prestera_msg_vtcam_resp) != 16); /* check events */ BUILD_BUG_ON(sizeof(struct prestera_msg_event_port) != 20); @@ -1044,225 +1025,159 @@ static void prestera_hw_remote_fc_to_eth(u8 fc, bool *pause, bool *asym_pause) } } -int prestera_hw_acl_ruleset_create(struct prestera_switch *sw, u16 *ruleset_id) +int prestera_hw_vtcam_create(struct prestera_switch *sw, + u8 lookup, const u32 *keymask, u32 *vtcam_id, + enum prestera_hw_vtcam_direction_t dir) { - struct prestera_msg_acl_ruleset_resp resp; - struct prestera_msg_acl_ruleset_req req; int err; + struct prestera_msg_vtcam_resp resp; + struct prestera_msg_vtcam_create_req req = { + .lookup = lookup, + .direction = dir, + }; + + if (keymask) + memcpy(req.keymask, keymask, sizeof(req.keymask)); + else + memset(req.keymask, 0, sizeof(req.keymask)); - err = prestera_cmd_ret(sw, PRESTERA_CMD_TYPE_ACL_RULESET_CREATE, + err = prestera_cmd_ret(sw, PRESTERA_CMD_TYPE_VTCAM_CREATE, &req.cmd, sizeof(req), &resp.ret, sizeof(resp)); if (err) return err; - *ruleset_id = __le16_to_cpu(resp.id); - + *vtcam_id = __le32_to_cpu(resp.vtcam_id); return 0; } -int prestera_hw_acl_ruleset_del(struct prestera_switch *sw, u16 ruleset_id) +int prestera_hw_vtcam_destroy(struct prestera_switch *sw, u32 vtcam_id) { - struct prestera_msg_acl_ruleset_req req = { - .id = __cpu_to_le16(ruleset_id), + struct prestera_msg_vtcam_destroy_req req = { + .vtcam_id = __cpu_to_le32(vtcam_id), }; - return prestera_cmd(sw, PRESTERA_CMD_TYPE_ACL_RULESET_DELETE, + return prestera_cmd(sw, PRESTERA_CMD_TYPE_VTCAM_DESTROY, &req.cmd, sizeof(req)); } -static int prestera_hw_acl_actions_put(struct prestera_msg_acl_action *action, - struct prestera_acl_rule *rule) +static int +prestera_acl_rule_add_put_action(struct prestera_msg_acl_action *action, + struct prestera_acl_hw_action_info *info) { - struct list_head *a_list = prestera_acl_rule_action_list_get(rule); - struct prestera_acl_rule_action_entry *a_entry; - int i = 0; - - list_for_each_entry(a_entry, a_list, list) { - action[i].id = __cpu_to_le32(a_entry->id); - - switch (a_entry->id) { - case PRESTERA_ACL_RULE_ACTION_ACCEPT: - case PRESTERA_ACL_RULE_ACTION_DROP: - case PRESTERA_ACL_RULE_ACTION_TRAP: - /* just rule action id, no specific data */ - break; - default: - return -EINVAL; - } + action->id = __cpu_to_le32(info->id); - i++; - } - - return 0; -} - -static int prestera_hw_acl_matches_put(struct prestera_msg_acl_match *match, - struct prestera_acl_rule *rule) -{ - struct list_head *m_list = prestera_acl_rule_match_list_get(rule); - struct prestera_acl_rule_match_entry *m_entry; - int i = 0; - - list_for_each_entry(m_entry, m_list, list) { - match[i].type = __cpu_to_le32(m_entry->type); - - switch (m_entry->type) { - case PRESTERA_ACL_RULE_MATCH_ENTRY_TYPE_ETH_TYPE: - case PRESTERA_ACL_RULE_MATCH_ENTRY_TYPE_L4_PORT_SRC: - case PRESTERA_ACL_RULE_MATCH_ENTRY_TYPE_L4_PORT_DST: - case PRESTERA_ACL_RULE_MATCH_ENTRY_TYPE_VLAN_ID: - case PRESTERA_ACL_RULE_MATCH_ENTRY_TYPE_VLAN_TPID: - match[i].keymask.u16.key = - __cpu_to_le16(m_entry->keymask.u16.key); - match[i].keymask.u16.mask = - __cpu_to_le16(m_entry->keymask.u16.mask); - break; - case PRESTERA_ACL_RULE_MATCH_ENTRY_TYPE_ICMP_TYPE: - case PRESTERA_ACL_RULE_MATCH_ENTRY_TYPE_ICMP_CODE: - case PRESTERA_ACL_RULE_MATCH_ENTRY_TYPE_IP_PROTO: - match[i].keymask.u8.key = m_entry->keymask.u8.key; - match[i].keymask.u8.mask = m_entry->keymask.u8.mask; - break; - case PRESTERA_ACL_RULE_MATCH_ENTRY_TYPE_ETH_SMAC: - case PRESTERA_ACL_RULE_MATCH_ENTRY_TYPE_ETH_DMAC: - memcpy(match[i].keymask.mac.key, - m_entry->keymask.mac.key, - sizeof(match[i].keymask.mac.key)); - memcpy(match[i].keymask.mac.mask, - m_entry->keymask.mac.mask, - sizeof(match[i].keymask.mac.mask)); - break; - case PRESTERA_ACL_RULE_MATCH_ENTRY_TYPE_IP_SRC: - case PRESTERA_ACL_RULE_MATCH_ENTRY_TYPE_IP_DST: - case PRESTERA_ACL_RULE_MATCH_ENTRY_TYPE_L4_PORT_RANGE_SRC: - case PRESTERA_ACL_RULE_MATCH_ENTRY_TYPE_L4_PORT_RANGE_DST: - match[i].keymask.u32.key = - __cpu_to_le32(m_entry->keymask.u32.key); - match[i].keymask.u32.mask = - __cpu_to_le32(m_entry->keymask.u32.mask); - break; - case PRESTERA_ACL_RULE_MATCH_ENTRY_TYPE_PORT: - match[i].keymask.u64.key = - __cpu_to_le64(m_entry->keymask.u64.key); - match[i].keymask.u64.mask = - __cpu_to_le64(m_entry->keymask.u64.mask); - break; - default: - return -EINVAL; - } - - i++; + switch (info->id) { + case PRESTERA_ACL_RULE_ACTION_ACCEPT: + case PRESTERA_ACL_RULE_ACTION_DROP: + case PRESTERA_ACL_RULE_ACTION_TRAP: + /* just rule action id, no specific data */ + break; + default: + return -EINVAL; } return 0; } -int prestera_hw_acl_rule_add(struct prestera_switch *sw, - struct prestera_acl_rule *rule, - u32 *rule_id) +int prestera_hw_vtcam_rule_add(struct prestera_switch *sw, + u32 vtcam_id, u32 prio, void *key, void *keymask, + struct prestera_acl_hw_action_info *act, + u8 n_act, u32 *rule_id) { - struct prestera_msg_acl_action *actions; - struct prestera_msg_acl_match *matches; - struct prestera_msg_acl_rule_resp resp; - struct prestera_msg_acl_rule_req *req; - u8 n_actions; - u8 n_matches; + struct prestera_msg_acl_action *actions_msg; + struct prestera_msg_vtcam_rule_add_req *req; + struct prestera_msg_vtcam_resp resp; void *buff; u32 size; int err; + u8 i; - n_actions = prestera_acl_rule_action_len(rule); - n_matches = prestera_acl_rule_match_len(rule); - - size = sizeof(*req) + sizeof(*actions) * n_actions + - sizeof(*matches) * n_matches; + size = sizeof(*req) + sizeof(*actions_msg) * n_act; buff = kzalloc(size, GFP_KERNEL); if (!buff) return -ENOMEM; req = buff; - actions = buff + sizeof(*req); - matches = buff + sizeof(*req) + sizeof(*actions) * n_actions; - - /* put acl actions into the message */ - err = prestera_hw_acl_actions_put(actions, rule); - if (err) - goto free_buff; + req->n_act = __cpu_to_le32(n_act); + actions_msg = buff + sizeof(*req); /* put acl matches into the message */ - err = prestera_hw_acl_matches_put(matches, rule); - if (err) - goto free_buff; + memcpy(req->key, key, sizeof(req->key)); + memcpy(req->keymask, keymask, sizeof(req->keymask)); + + /* put acl actions into the message */ + for (i = 0; i < n_act; i++) { + err = prestera_acl_rule_add_put_action(&actions_msg[i], + &act[i]); + if (err) + goto free_buff; + } - req->ruleset_id = __cpu_to_le16(prestera_acl_rule_ruleset_id_get(rule)); - req->priority = __cpu_to_le32(prestera_acl_rule_priority_get(rule)); - req->n_actions = prestera_acl_rule_action_len(rule); - req->n_matches = prestera_acl_rule_match_len(rule); + req->vtcam_id = __cpu_to_le32(vtcam_id); + req->prio = __cpu_to_le32(prio); - err = prestera_cmd_ret(sw, PRESTERA_CMD_TYPE_ACL_RULE_ADD, + err = prestera_cmd_ret(sw, PRESTERA_CMD_TYPE_VTCAM_RULE_ADD, &req->cmd, size, &resp.ret, sizeof(resp)); if (err) goto free_buff; - *rule_id = __le32_to_cpu(resp.id); + *rule_id = __le32_to_cpu(resp.rule_id); free_buff: kfree(buff); return err; } -int prestera_hw_acl_rule_del(struct prestera_switch *sw, u32 rule_id) +int prestera_hw_vtcam_rule_del(struct prestera_switch *sw, + u32 vtcam_id, u32 rule_id) { - struct prestera_msg_acl_rule_req req = { + struct prestera_msg_vtcam_rule_del_req req = { + .vtcam_id = __cpu_to_le32(vtcam_id), .id = __cpu_to_le32(rule_id) }; - return prestera_cmd(sw, PRESTERA_CMD_TYPE_ACL_RULE_DELETE, + return prestera_cmd(sw, PRESTERA_CMD_TYPE_VTCAM_RULE_DELETE, &req.cmd, sizeof(req)); } -int prestera_hw_acl_rule_stats_get(struct prestera_switch *sw, u32 rule_id, - u64 *packets, u64 *bytes) +int prestera_hw_vtcam_iface_bind(struct prestera_switch *sw, + struct prestera_acl_iface *iface, + u32 vtcam_id, u16 pcl_id) { - struct prestera_msg_acl_rule_stats_resp resp; - struct prestera_msg_acl_rule_req req = { - .id = __cpu_to_le32(rule_id) + struct prestera_msg_vtcam_bind_req req = { + .vtcam_id = __cpu_to_le32(vtcam_id), + .type = __cpu_to_le16(iface->type), + .pcl_id = __cpu_to_le16(pcl_id) }; - int err; - - err = prestera_cmd_ret(sw, PRESTERA_CMD_TYPE_ACL_RULE_STATS_GET, - &req.cmd, sizeof(req), &resp.ret, sizeof(resp)); - if (err) - return err; - *packets = __le64_to_cpu(resp.packets); - *bytes = __le64_to_cpu(resp.bytes); - - return 0; -} - -int prestera_hw_acl_port_bind(const struct prestera_port *port, u16 ruleset_id) -{ - struct prestera_msg_acl_ruleset_bind_req req = { - .port = __cpu_to_le32(port->hw_id), - .dev = __cpu_to_le32(port->dev_id), - .ruleset_id = __cpu_to_le16(ruleset_id), - }; + if (iface->type == PRESTERA_ACL_IFACE_TYPE_PORT) { + req.port.dev_id = __cpu_to_le32(iface->port->dev_id); + req.port.hw_id = __cpu_to_le32(iface->port->hw_id); + } else { + req.index = __cpu_to_le32(iface->index); + } - return prestera_cmd(port->sw, PRESTERA_CMD_TYPE_ACL_PORT_BIND, + return prestera_cmd(sw, PRESTERA_CMD_TYPE_VTCAM_IFACE_BIND, &req.cmd, sizeof(req)); } -int prestera_hw_acl_port_unbind(const struct prestera_port *port, - u16 ruleset_id) +int prestera_hw_vtcam_iface_unbind(struct prestera_switch *sw, + struct prestera_acl_iface *iface, + u32 vtcam_id) { - struct prestera_msg_acl_ruleset_bind_req req = { - .port = __cpu_to_le32(port->hw_id), - .dev = __cpu_to_le32(port->dev_id), - .ruleset_id = __cpu_to_le16(ruleset_id), + struct prestera_msg_vtcam_bind_req req = { + .vtcam_id = __cpu_to_le32(vtcam_id), + .type = __cpu_to_le16(iface->type) }; - return prestera_cmd(port->sw, PRESTERA_CMD_TYPE_ACL_PORT_UNBIND, + if (iface->type == PRESTERA_ACL_IFACE_TYPE_PORT) { + req.port.dev_id = __cpu_to_le32(iface->port->dev_id); + req.port.hw_id = __cpu_to_le32(iface->port->hw_id); + } else { + req.index = __cpu_to_le32(iface->index); + } + + return prestera_cmd(sw, PRESTERA_CMD_TYPE_VTCAM_IFACE_UNBIND, &req.cmd, sizeof(req)); } diff --git a/drivers/net/ethernet/marvell/prestera/prestera_hw.h b/drivers/net/ethernet/marvell/prestera/prestera_hw.h index 57a3c2e5b112..6b7a9f8e2ea2 100644 --- a/drivers/net/ethernet/marvell/prestera/prestera_hw.h +++ b/drivers/net/ethernet/marvell/prestera/prestera_hw.h @@ -5,6 +5,7 @@ #define _PRESTERA_HW_H_ #include +#include "prestera_acl.h" enum prestera_accept_frm_type { PRESTERA_ACCEPT_FRAME_TYPE_TAGGED, @@ -111,18 +112,24 @@ enum prestera_hw_cpu_code_cnt_t { PRESTERA_HW_CPU_CODE_CNT_TYPE_TRAP = 1, }; +enum prestera_hw_vtcam_direction_t { + PRESTERA_HW_VTCAM_DIR_INGRESS = 0, + PRESTERA_HW_VTCAM_DIR_EGRESS = 1, +}; + struct prestera_switch; struct prestera_port; struct prestera_port_stats; struct prestera_port_caps; enum prestera_event_type; struct prestera_event; -struct prestera_acl_rule; typedef void (*prestera_event_cb_t) (struct prestera_switch *sw, struct prestera_event *evt, void *arg); struct prestera_rxtx_params; +struct prestera_acl_hw_action_info; +struct prestera_acl_iface; /* Switch API */ int prestera_hw_switch_init(struct prestera_switch *sw); @@ -186,21 +193,23 @@ int prestera_hw_bridge_delete(struct prestera_switch *sw, u16 bridge_id); int prestera_hw_bridge_port_add(struct prestera_port *port, u16 bridge_id); int prestera_hw_bridge_port_delete(struct prestera_port *port, u16 bridge_id); -/* ACL API */ -int prestera_hw_acl_ruleset_create(struct prestera_switch *sw, - u16 *ruleset_id); -int prestera_hw_acl_ruleset_del(struct prestera_switch *sw, - u16 ruleset_id); -int prestera_hw_acl_rule_add(struct prestera_switch *sw, - struct prestera_acl_rule *rule, - u32 *rule_id); -int prestera_hw_acl_rule_del(struct prestera_switch *sw, u32 rule_id); -int prestera_hw_acl_rule_stats_get(struct prestera_switch *sw, - u32 rule_id, u64 *packets, u64 *bytes); -int prestera_hw_acl_port_bind(const struct prestera_port *port, - u16 ruleset_id); -int prestera_hw_acl_port_unbind(const struct prestera_port *port, - u16 ruleset_id); +/* vTCAM API */ +int prestera_hw_vtcam_create(struct prestera_switch *sw, + u8 lookup, const u32 *keymask, u32 *vtcam_id, + enum prestera_hw_vtcam_direction_t direction); +int prestera_hw_vtcam_rule_add(struct prestera_switch *sw, u32 vtcam_id, + u32 prio, void *key, void *keymask, + struct prestera_acl_hw_action_info *act, + u8 n_act, u32 *rule_id); +int prestera_hw_vtcam_rule_del(struct prestera_switch *sw, + u32 vtcam_id, u32 rule_id); +int prestera_hw_vtcam_destroy(struct prestera_switch *sw, u32 vtcam_id); +int prestera_hw_vtcam_iface_bind(struct prestera_switch *sw, + struct prestera_acl_iface *iface, + u32 vtcam_id, u16 pcl_id); +int prestera_hw_vtcam_iface_unbind(struct prestera_switch *sw, + struct prestera_acl_iface *iface, + u32 vtcam_id); /* SPAN API */ int prestera_hw_span_get(const struct prestera_port *port, u8 *span_id); diff --git a/drivers/net/ethernet/marvell/prestera/prestera_span.c b/drivers/net/ethernet/marvell/prestera/prestera_span.c index 3cafca827bb7..845e9d8c8cc7 100644 --- a/drivers/net/ethernet/marvell/prestera/prestera_span.c +++ b/drivers/net/ethernet/marvell/prestera/prestera_span.c @@ -7,6 +7,7 @@ #include "prestera.h" #include "prestera_hw.h" #include "prestera_acl.h" +#include "prestera_flow.h" #include "prestera_span.h" struct prestera_span_entry { From patchwork Tue Nov 23 16:58:01 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Volodymyr Mytnyk X-Patchwork-Id: 12634809 X-Patchwork-Delegate: kuba@kernel.org Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 28AA5C433F5 for ; Tue, 23 Nov 2021 17:00:10 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S236804AbhKWRDL (ORCPT ); Tue, 23 Nov 2021 12:03:11 -0500 Received: from mail-eopbgr60115.outbound.protection.outlook.com ([40.107.6.115]:58118 "EHLO EUR04-DB3-obe.outbound.protection.outlook.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S238389AbhKWRDJ (ORCPT ); Tue, 23 Nov 2021 12:03:09 -0500 ARC-Seal: i=1; a=rsa-sha256; s=arcselector9901; d=microsoft.com; cv=none; b=bDwtUKgLOMrajlOQ2ybkk00ozxOD4PJPfvALcbYfV0rSLvO2zRGZsTRXvU1emw49iRxE0U4RgpCZfKz7pmnPAYTt1m6VJyoi+sGKVE2xhOoe7U81C4bGJvHZWierQP4C7lqvFnjkAP9tKlPGr1ucwvvR0+09y2HoZZ334gda7WNQLQHDGLeh+Zza6AjbMYsiOfldbMGxjAwwl9b5Sh3tufMJrleBAbTeWUNUHWjJVcgm5AbVSr9xou1RXN8+EgFO6wrfjp20BSpufj/Eduby0QhFZu6ADxinRKBTCp/TeSsQ4S81GKerMdnQgYv0I8AqogAfvpfX2k2yS+jz8wuz2w== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=arcselector9901; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-AntiSpam-MessageData-ChunkCount:X-MS-Exchange-AntiSpam-MessageData-0:X-MS-Exchange-AntiSpam-MessageData-1; bh=ZLT7Sk7g/lu1vi76GLmPoNudJP5brjny1BO2UHR5rLU=; b=I9BWfbu0pJsrqL+kCkznBXvWepA+RYHI1/OmgDb4Dro/KdffchOmk0q5dnjJeyVmLzYIqg3KFnHexOqvzIGyqPSBnUcc/n2wQNmImY2LZT8+m0M6EoO0hSswO+tFGWfyvZku0Z/tXvzPlR2b2r7Nf27GI1YrvWJ/fc6TemmS0z+Hu0f+RqJggaLM0AW0ugL5EduMt5QsGtHVQAxNMQxO8LHG2AuBBhQTn5fkQmB26FvNwVvea2vDwR5r6FolybdrG0/Dql5/FhXdvwAxeZW/QSRrZkuRT7QBLerfYdFaC6Uus27TXJ2AeITHbru7PDiYfOLJug82MMQHfxi8J1f7Iw== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=pass smtp.mailfrom=plvision.eu; dmarc=pass action=none header.from=plvision.eu; dkim=pass header.d=plvision.eu; arc=none DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=plvision.eu; s=selector2; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=ZLT7Sk7g/lu1vi76GLmPoNudJP5brjny1BO2UHR5rLU=; b=dH0II1KlZa5G60eJHbKGDpi3igUKYKJHzaBwy/lF93UJoOUm09GK/VZLfuneSgQ8YVPv2mrj9EMA8Zs8tgT9g7LTVDzZ++qI+uHedTeBTrG2sdBbKI0fTmCTEV/DAYXWxW5M2xksTQuty/YQ7CVD17t9vr8xo+yO5qZGAWdXObY= Authentication-Results: dkim=none (message not signed) header.d=none;dmarc=none action=none header.from=plvision.eu; Received: from VI1P190MB0734.EURP190.PROD.OUTLOOK.COM (2603:10a6:800:123::23) by VE1P190MB0830.EURP190.PROD.OUTLOOK.COM (2603:10a6:800:1a9::5) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.4713.24; Tue, 23 Nov 2021 16:59:59 +0000 Received: from VI1P190MB0734.EURP190.PROD.OUTLOOK.COM ([fe80::e15a:32ff:b93c:d136]) by VI1P190MB0734.EURP190.PROD.OUTLOOK.COM ([fe80::e15a:32ff:b93c:d136%4]) with mapi id 15.20.4713.026; Tue, 23 Nov 2021 16:59:59 +0000 From: Volodymyr Mytnyk To: netdev@vger.kernel.org Cc: Taras Chornyi , Mickey Rachamim , Serhiy Pshyk , Volodymyr Mytnyk , Taras Chornyi , "David S. Miller" , Jakub Kicinski , linux-kernel@vger.kernel.org, Serhiy Boiko Subject: [PATCH net-next 2/3] net: prestera: add counter HW API Date: Tue, 23 Nov 2021 18:58:01 +0200 Message-Id: <1637686684-2492-3-git-send-email-volodymyr.mytnyk@plvision.eu> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1637686684-2492-1-git-send-email-volodymyr.mytnyk@plvision.eu> References: <1637686684-2492-1-git-send-email-volodymyr.mytnyk@plvision.eu> X-ClientProxiedBy: AS8PR04CA0203.eurprd04.prod.outlook.com (2603:10a6:20b:2f3::28) To VI1P190MB0734.EURP190.PROD.OUTLOOK.COM (2603:10a6:800:123::23) MIME-Version: 1.0 Received: from vmytnykub.x.ow.s (217.20.186.93) by AS8PR04CA0203.eurprd04.prod.outlook.com (2603:10a6:20b:2f3::28) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256) id 15.20.4713.19 via Frontend Transport; Tue, 23 Nov 2021 16:59:58 +0000 X-MS-PublicTrafficType: Email X-MS-Office365-Filtering-Correlation-Id: dcc351ca-d714-404b-40e7-08d9aea2aeb5 X-MS-TrafficTypeDiagnostic: VE1P190MB0830: X-Microsoft-Antispam-PRVS: X-MS-Oob-TLC-OOBClassifiers: OLM:1303; X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0; X-Microsoft-Antispam-Message-Info: QXtpt2jxDwaHIAVB3zUFVhvt3z/DDMT8l1QlF8Yqb9/kbFJPnrYf98I8qzMnKWtMdxJ+rMWtN+sOTpebyU/BrNdk7gP9kiG2CoZSdDKc5MQp+bLbUQmRZvkf956E4IUN7JqFiZ149Pw7k6/jgXHwvLFmZouOiPZ/aH9UQMUYsWbJ9IUzqlD1/qEu360kO/J0his1B0e0LUw/KgNNUIWTj9tYM8fHKgZDqYZ7E32a8RIIkKcTyXKYNhgX2KYUcZ7w7T+s8I0Mai+gg0t5jZqvscd0Vos9rTvDtSSY/hWkxk1cCqZu6cmnn7+0KAcEsjS7Zuz/NFyfeXoxZBmhR8P5fR63KU0HAbUWq1VCBXwAjddRqmx5s34cIBuYZISZYrFu+IvT//v0SG0cSqMpgjYbfwSHhdOgrmhAg1GYE5r4yjUBBM4DkD9in+CGr19X0EKfLgotZ5/bspXWldUztuAunkwKZmPGFIJD5h4S2Nl+dhP9aBSK40RwWu4QWK10NinFPG3wGvn0thJN7W4xLFS2sX6m2SEYPPvuYsZcYnZTScaH4upbLOEcOPmyRRmVmsAVcxCm5WmThDoeidI8tGhFZyoSBUHol96O/WsRctVIBpFlYPcS9O3IlKrVCcxONQvG1qm/ZH6F6q0OKQVa+7k1bHcxDV0BKLHq64MlYgh2Ud4r6Jhux8+OWtz52fyTkWQjBlRcGUAZwUx+YM+rFHtzkg== X-Forefront-Antispam-Report: CIP:255.255.255.255;CTRY:;LANG:en;SCL:1;SRV:;IPV:NLI;SFV:NSPM;H:VI1P190MB0734.EURP190.PROD.OUTLOOK.COM;PTR:;CAT:NONE;SFS:(136003)(376002)(39840400004)(366004)(396003)(346002)(36756003)(26005)(956004)(2616005)(6666004)(83380400001)(66946007)(8936002)(8676002)(6512007)(38350700002)(66556008)(66476007)(52116002)(316002)(186003)(30864003)(2906002)(6916009)(38100700002)(44832011)(86362001)(54906003)(4326008)(5660300002)(508600001)(6486002)(6506007);DIR:OUT;SFP:1102; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 1 X-MS-Exchange-AntiSpam-MessageData-0: +h/K/Tgzo87tsTGpQDxS+01qY81nQsahp8L9rbBoZpA2hhNVRUXNTkxVF1Szz/r52sC8OzLxyDboAIVC3UcBFN7KtbMS1wi0c0yJR3KZaJ+PpgR/99Tbba14bwVZl4RRhw64DUHJL7M+blcT7IMKvY9iUBnLd4zs0RwNH4hG39/1J5gxSsDY58bYo2Vmi5v7h0C+ud8plgp5a5F5+A9wAey9k61IdmYY3radp2VVI2msmyr/a441Ar6W2liJND5hdpENEHLhKtcSmtRMSySEvB0ArauAc6ZDakxncXlZ2PoRjNhIVXuVI1zIXuQqOTr/Gmu9PdYVj9KkWlFY5Q2dkJKseRUiIWDSpZktO13XkxSNmGaydXVnVwHaL3x6qNYbH/rWzkjQFFoKAwTzPQOkTvdahuWZZhFgzYmK2W5slv5E5Dgp9mfwT6WxMT3ZlekQM3BoDak3YilxXgCkIUqHL+via+Ef/ex9hlCcwZx3ykRzVFLfBLAhD96zwUB/HrR4iRVZw9LO7FLu6ouC0wn50j0AFInTHL9KYA4JErPiZVc3y9fXjKir9+aBfwgacCEi1bbsiYXiFiSbjDge9+lmt6SV7z0FmDf3FRfGHplPzGET6o3QCdeHB+4qdNnG7ZJSHIxYGeeq5KSFm35Fb2f9OeJ1ZWIY/ZgexA8AHHbFBA2CLk7eNBbj3W9cQmClZ0LJPHNMgX9mf/mbSxFJmCvyNgA5dRWTjYoj98Ve6c8gK1QPVzWMY3MfSSyO3UmmKxL8iPljA8TQBJLGoTR5DUHJtDJrzdFwD+UXreA7jAMIi2S64GH/YeM7pB/aJg9yLKUsU5JYFJe0j9bVQ/Xxpk7vlabd/XxYqSBSKN9cWlYL4QBWO2/Yjh6yPRPRC6isgEcihYCYwJi0Po1oWrd9CszfUobsmaRD5Gn+RjK3waq2Ix52vWAXcfX3T4Xec6O4iZueRVKSB9uhIKaSw7BcYWDIAsolEIPsKuSn/WnbA5CaqfGvLddR0gsH5a7+dxsGO3+xZkSwJCK1DtTJGUSfMqjKieFmrdPgVSaqDUezuwrWIPlnxB57r6kVDYVuWzXiFnYHuu+89MEoEQqMzH1sHba4wflI3gZBagYnr6NuOdrwr8CnJPzkuaxWUwvBvaycG0bg7N6utpDDc8wLju6ptWAc7av0lPJfKRjO9+C+XEmYbIPjPTwzdei0Zmi42VehM8UvdWlyYuSakVXYeSFXumgwQ8KXj//VdnsEf4SDZG/Aht64AsVNkZfsQ9uwoMdJ4CHjIzxlcviTbQyiuHH/pqn17EnMSm6cPXVtb9ieFiUILSiva5RFw4XGLyr8XWd3xZcZ38PtFAkBoeogzo0aRhSvkdA3xNHedZohLIvbRwEsAgWlBqv9JEFY46RiLt/E4CxmkNe0VJqRrEVDXxQsdKQuv0YfWpLpSm0W6bTq1X0e24lf+GBz8jl6EgiI+FILxDYzT8d/capd9epQ+lYMnwuD9bLmIX+sAaojX3uydTVWoT8e6jEyqFxt7nu4Piv9psWe93HLkMF5/K4i2Ghwc6wFg0pIVF/kPwe8mKQzVToB/PWeqv+23hUgGtw0kB210+EuFCAOCAcqhfzJY4xvfKzxJ26Q0AH0z2T+z7fvywlG99jE8JGJ3ODYQuRYpql4hbKE9+KBtoKJLTGTcTK9lL2QAA== X-OriginatorOrg: plvision.eu X-MS-Exchange-CrossTenant-Network-Message-Id: dcc351ca-d714-404b-40e7-08d9aea2aeb5 X-MS-Exchange-CrossTenant-AuthSource: VI1P190MB0734.EURP190.PROD.OUTLOOK.COM X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 23 Nov 2021 16:59:59.0128 (UTC) X-MS-Exchange-CrossTenant-FromEntityHeader: Hosted X-MS-Exchange-CrossTenant-Id: 03707b74-30f3-46b6-a0e0-ff0a7438c9c4 X-MS-Exchange-CrossTenant-MailboxType: HOSTED X-MS-Exchange-CrossTenant-UserPrincipalName: 1t8aneW+bBZFd/EwikN2XDw+dc5wE0HVqlthcnpouWNXK6h31gqcP8SRyH2ZwELE08SB34ORjn4TmWSuI8KG+rFeO8rzdagsH2bfFvPOtoc= X-MS-Exchange-Transport-CrossTenantHeadersStamped: VE1P190MB0830 Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org X-Patchwork-Delegate: kuba@kernel.org From: Volodymyr Mytnyk Add counter API for getting HW statistics. - HW statistics gathered by this API are deleyed. - Batch of conters is supported. - acl stat is supported. Co-developed-by: Serhiy Boiko Signed-off-by: Serhiy Boiko Signed-off-by: Volodymyr Mytnyk --- drivers/net/ethernet/marvell/prestera/Makefile | 2 +- drivers/net/ethernet/marvell/prestera/prestera.h | 1 + .../net/ethernet/marvell/prestera/prestera_acl.h | 7 + .../ethernet/marvell/prestera/prestera_counter.c | 474 +++++++++++++++++++++ .../ethernet/marvell/prestera/prestera_counter.h | 30 ++ .../net/ethernet/marvell/prestera/prestera_hw.c | 140 +++++- .../net/ethernet/marvell/prestera/prestera_hw.h | 21 + .../net/ethernet/marvell/prestera/prestera_main.c | 8 + 8 files changed, 681 insertions(+), 2 deletions(-) create mode 100644 drivers/net/ethernet/marvell/prestera/prestera_counter.c create mode 100644 drivers/net/ethernet/marvell/prestera/prestera_counter.h diff --git a/drivers/net/ethernet/marvell/prestera/Makefile b/drivers/net/ethernet/marvell/prestera/Makefile index 0609df8b913d..48dbcb2baf8f 100644 --- a/drivers/net/ethernet/marvell/prestera/Makefile +++ b/drivers/net/ethernet/marvell/prestera/Makefile @@ -3,6 +3,6 @@ obj-$(CONFIG_PRESTERA) += prestera.o prestera-objs := prestera_main.o prestera_hw.o prestera_dsa.o \ prestera_rxtx.o prestera_devlink.o prestera_ethtool.o \ prestera_switchdev.o prestera_acl.o prestera_flow.o \ - prestera_flower.o prestera_span.o + prestera_flower.o prestera_span.o prestera_counter.o obj-$(CONFIG_PRESTERA_PCI) += prestera_pci.o diff --git a/drivers/net/ethernet/marvell/prestera/prestera.h b/drivers/net/ethernet/marvell/prestera/prestera.h index 2a4c14c704c0..797b2e4d3551 100644 --- a/drivers/net/ethernet/marvell/prestera/prestera.h +++ b/drivers/net/ethernet/marvell/prestera/prestera.h @@ -248,6 +248,7 @@ struct prestera_switch { u32 mtu_max; u8 id; struct prestera_lag *lags; + struct prestera_counter *counter; u8 lag_member_max; u8 lag_max; }; diff --git a/drivers/net/ethernet/marvell/prestera/prestera_acl.h b/drivers/net/ethernet/marvell/prestera/prestera_acl.h index b7f9a7904508..a1a99f026b87 100644 --- a/drivers/net/ethernet/marvell/prestera/prestera_acl.h +++ b/drivers/net/ethernet/marvell/prestera/prestera_acl.h @@ -60,6 +60,10 @@ struct prestera_acl_match { __be32 mask[__PRESTERA_ACL_RULE_MATCH_TYPE_MAX]; }; +struct prestera_acl_action_count { + u32 id; +}; + struct prestera_acl_rule_entry_key { u32 prio; struct prestera_acl_match match; @@ -67,6 +71,9 @@ struct prestera_acl_rule_entry_key { struct prestera_acl_hw_action_info { enum prestera_acl_rule_action id; + union { + struct prestera_acl_action_count count; + }; }; /* This struct (arg) used only to be passed as parameter for diff --git a/drivers/net/ethernet/marvell/prestera/prestera_counter.c b/drivers/net/ethernet/marvell/prestera/prestera_counter.c new file mode 100644 index 000000000000..82de93913ccb --- /dev/null +++ b/drivers/net/ethernet/marvell/prestera/prestera_counter.c @@ -0,0 +1,474 @@ +// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0 +/* Copyright (c) 2021 Marvell International Ltd. All rights reserved */ + +#include "prestera.h" +#include "prestera_hw.h" +#include "prestera_acl.h" +#include "prestera_counter.h" + +#define COUNTER_POLL_TIME (msecs_to_jiffies(1000)) +#define COUNTER_RESCHED_TIME (msecs_to_jiffies(50)) +#define COUNTER_BULK_SIZE (256) + +struct prestera_counter { + struct prestera_switch *sw; + struct delayed_work stats_dw; + bool is_fetching; + u32 total_read; + struct mutex mtx; /* protect block_list */ + struct prestera_counter_block **block_list; + u32 block_list_len; + u32 curr_idx; +}; + +struct prestera_counter_block { + struct list_head list; + u32 id; + u32 offset; + u32 num_counters; + u32 client; + struct idr counter_idr; + bool full; + bool is_updating; + refcount_t refcnt; + struct mutex mtx; /* protect stats and counter_idr */ + struct prestera_counter_stats *stats; + u8 *counter_flag; +}; + +enum { + COUNTER_FLAG_READY = 0, + COUNTER_FLAG_INVALID = 1 +}; + +static inline bool +prestera_counter_is_ready(struct prestera_counter_block *block, u32 id) +{ + return block->counter_flag[id - block->offset] == COUNTER_FLAG_READY; +} + +static void prestera_counter_lock(struct prestera_counter *counter) +{ + mutex_lock(&counter->mtx); +} + +static void prestera_counter_unlock(struct prestera_counter *counter) +{ + mutex_unlock(&counter->mtx); +} + +static void prestera_counter_block_lock(struct prestera_counter_block *block) +{ + mutex_lock(&block->mtx); +} + +static void prestera_counter_block_unlock(struct prestera_counter_block *block) +{ + mutex_unlock(&block->mtx); +} + +static bool prestera_counter_block_incref(struct prestera_counter_block *block) +{ + return refcount_inc_not_zero(&block->refcnt); +} + +static bool prestera_counter_block_decref(struct prestera_counter_block *block) +{ + return refcount_dec_and_test(&block->refcnt); +} + +/* must be called with prestera_counter_block_lock() */ +static void prestera_counter_stats_clear(struct prestera_counter_block *block, + u32 counter_id) +{ + memset(&block->stats[counter_id - block->offset], 0, + sizeof(*block->stats)); +} + +static struct prestera_counter_block * +prestera_counter_block_lookup_not_full(struct prestera_counter *counter, + u32 client) +{ + u32 i; + + prestera_counter_lock(counter); + for (i = 0; i < counter->block_list_len; i++) { + if (counter->block_list[i] && + counter->block_list[i]->client == client && + !counter->block_list[i]->full && + prestera_counter_block_incref(counter->block_list[i])) { + prestera_counter_unlock(counter); + return counter->block_list[i]; + } + } + prestera_counter_unlock(counter); + + return NULL; +} + +static int prestera_counter_block_list_add(struct prestera_counter *counter, + struct prestera_counter_block *block) +{ + struct prestera_counter_block **arr; + u32 i; + + prestera_counter_lock(counter); + + for (i = 0; i < counter->block_list_len; i++) { + if (counter->block_list[i]) + continue; + + counter->block_list[i] = block; + prestera_counter_unlock(counter); + return 0; + } + + arr = krealloc(counter->block_list, (counter->block_list_len + 1) * + sizeof(*counter->block_list), GFP_KERNEL); + if (!arr) { + prestera_counter_unlock(counter); + return -ENOMEM; + } + + counter->block_list = arr; + counter->block_list[counter->block_list_len] = block; + counter->block_list_len++; + prestera_counter_unlock(counter); + return 0; +} + +static struct prestera_counter_block * +prestera_counter_block_get(struct prestera_counter *counter, u32 client) +{ + struct prestera_counter_block *block; + int err; + + block = prestera_counter_block_lookup_not_full(counter, client); + if (!block) { + block = kzalloc(sizeof(*block), GFP_KERNEL); + if (!block) + return ERR_PTR(-ENOMEM); + + err = prestera_hw_counter_block_get(counter->sw, client, + &block->id, &block->offset, + &block->num_counters); + if (err) + goto err_block; + + block->stats = kcalloc(block->num_counters, + sizeof(*block->stats), GFP_KERNEL); + if (!block->stats) { + err = -ENOMEM; + goto err_stats; + } + + block->counter_flag = kcalloc(block->num_counters, + sizeof(*block->counter_flag), + GFP_KERNEL); + if (!block->counter_flag) { + err = -ENOMEM; + goto err_flag; + } + + block->client = client; + mutex_init(&block->mtx); + refcount_set(&block->refcnt, 1); + idr_init_base(&block->counter_idr, block->offset); + + err = prestera_counter_block_list_add(counter, block); + if (err) + goto err_list_add; + } + + return block; + +err_list_add: + idr_destroy(&block->counter_idr); + mutex_destroy(&block->mtx); + kfree(block->counter_flag); +err_flag: + kfree(block->stats); +err_stats: + prestera_hw_counter_block_release(counter->sw, block->id); +err_block: + kfree(block); + return ERR_PTR(err); +} + +static void prestera_counter_block_put(struct prestera_counter *counter, + struct prestera_counter_block *block) +{ + u32 i; + + if (!prestera_counter_block_decref(block)) + return; + + prestera_counter_lock(counter); + for (i = 0; i < counter->block_list_len; i++) { + if (counter->block_list[i] && + counter->block_list[i]->id == block->id) { + counter->block_list[i] = NULL; + break; + } + } + prestera_counter_unlock(counter); + + WARN_ON(!idr_is_empty(&block->counter_idr)); + + prestera_hw_counter_block_release(counter->sw, block->id); + idr_destroy(&block->counter_idr); + mutex_destroy(&block->mtx); + kfree(block->stats); + kfree(block); +} + +static int prestera_counter_get_vacant(struct prestera_counter_block *block, + u32 *id) +{ + int free_id; + + if (block->full) + return -ENOSPC; + + prestera_counter_block_lock(block); + free_id = idr_alloc_cyclic(&block->counter_idr, NULL, block->offset, + block->offset + block->num_counters, + GFP_KERNEL); + if (free_id < 0) { + if (free_id == -ENOSPC) + block->full = true; + + prestera_counter_block_unlock(block); + return free_id; + } + *id = free_id; + prestera_counter_block_unlock(block); + + return 0; +} + +int prestera_counter_get(struct prestera_counter *counter, u32 client, + struct prestera_counter_block **bl, u32 *counter_id) +{ + struct prestera_counter_block *block; + int err; + u32 id; + +get_next_block: + block = prestera_counter_block_get(counter, client); + if (IS_ERR(block)) + return PTR_ERR(block); + + err = prestera_counter_get_vacant(block, &id); + if (err) { + prestera_counter_block_put(counter, block); + + if (err == -ENOSPC) + goto get_next_block; + + return err; + } + + prestera_counter_block_lock(block); + if (block->is_updating) + block->counter_flag[id - block->offset] = COUNTER_FLAG_INVALID; + prestera_counter_block_unlock(block); + + *counter_id = id; + *bl = block; + + return 0; +} + +void prestera_counter_put(struct prestera_counter *counter, + struct prestera_counter_block *block, u32 counter_id) +{ + if (!block) + return; + + prestera_counter_block_lock(block); + idr_remove(&block->counter_idr, counter_id); + block->full = false; + prestera_counter_stats_clear(block, counter_id); + prestera_counter_block_unlock(block); + + prestera_hw_counter_clear(counter->sw, block->id, counter_id); + prestera_counter_block_put(counter, block); +} + +static u32 prestera_counter_block_idx_next(struct prestera_counter *counter, + u32 curr_idx) +{ + u32 idx, i, start = curr_idx + 1; + + prestera_counter_lock(counter); + for (i = 0; i < counter->block_list_len; i++) { + idx = (start + i) % counter->block_list_len; + if (!counter->block_list[idx]) + continue; + + prestera_counter_unlock(counter); + return idx; + } + prestera_counter_unlock(counter); + + return 0; +} + +static struct prestera_counter_block * +prestera_counter_block_get_by_idx(struct prestera_counter *counter, u32 idx) +{ + if (idx >= counter->block_list_len) + return NULL; + + prestera_counter_lock(counter); + + if (!counter->block_list[idx] || + !prestera_counter_block_incref(counter->block_list[idx])) { + prestera_counter_unlock(counter); + return NULL; + } + + prestera_counter_unlock(counter); + return counter->block_list[idx]; +} + +static void prestera_counter_stats_work(struct work_struct *work) +{ + struct delayed_work *dl_work = + container_of(work, struct delayed_work, work); + struct prestera_counter *counter = + container_of(dl_work, struct prestera_counter, stats_dw); + struct prestera_counter_block *block; + u32 resched_time = COUNTER_POLL_TIME; + u32 count = COUNTER_BULK_SIZE; + bool done = false; + int err; + u32 i; + + block = prestera_counter_block_get_by_idx(counter, counter->curr_idx); + if (!block) { + if (counter->is_fetching) + goto abort; + + goto next; + } + + if (!counter->is_fetching) { + err = prestera_hw_counter_trigger(counter->sw, block->id); + if (err) + goto abort; + + prestera_counter_block_lock(block); + block->is_updating = true; + prestera_counter_block_unlock(block); + + counter->is_fetching = true; + counter->total_read = 0; + resched_time = COUNTER_RESCHED_TIME; + goto resched; + } + + prestera_counter_block_lock(block); + err = prestera_hw_counters_get(counter->sw, counter->total_read, + &count, &done, + &block->stats[counter->total_read]); + prestera_counter_block_unlock(block); + if (err) + goto abort; + + counter->total_read += count; + if (!done || counter->total_read < block->num_counters) { + resched_time = COUNTER_RESCHED_TIME; + goto resched; + } + + for (i = 0; i < block->num_counters; i++) { + if (block->counter_flag[i] == COUNTER_FLAG_INVALID) { + prestera_counter_block_lock(block); + block->counter_flag[i] = COUNTER_FLAG_READY; + memset(&block->stats[i], 0, sizeof(*block->stats)); + prestera_counter_block_unlock(block); + } + } + + prestera_counter_block_lock(block); + block->is_updating = false; + prestera_counter_block_unlock(block); + + goto next; +abort: + prestera_hw_counter_abort(counter->sw); +next: + counter->is_fetching = false; + counter->curr_idx = + prestera_counter_block_idx_next(counter, counter->curr_idx); +resched: + if (block) + prestera_counter_block_put(counter, block); + + schedule_delayed_work(&counter->stats_dw, resched_time); +} + +/* Can be executed without rtnl_lock(). + * So pay attention when something changing. + */ +int prestera_counter_stats_get(struct prestera_counter *counter, + struct prestera_counter_block *block, + u32 counter_id, u64 *packets, u64 *bytes) +{ + if (!block || !prestera_counter_is_ready(block, counter_id)) { + *packets = 0; + *bytes = 0; + return 0; + } + + prestera_counter_block_lock(block); + *packets = block->stats[counter_id - block->offset].packets; + *bytes = block->stats[counter_id - block->offset].bytes; + + prestera_counter_stats_clear(block, counter_id); + prestera_counter_block_unlock(block); + + return 0; +} + +int prestera_counter_init(struct prestera_switch *sw) +{ + struct prestera_counter *counter; + + counter = kzalloc(sizeof(*counter), GFP_KERNEL); + if (!counter) + return -ENOMEM; + + counter->block_list = kzalloc(sizeof(*counter->block_list), GFP_KERNEL); + if (!counter->block_list) { + kfree(counter); + return -ENOMEM; + } + + mutex_init(&counter->mtx); + counter->block_list_len = 1; + counter->sw = sw; + sw->counter = counter; + + INIT_DELAYED_WORK(&counter->stats_dw, prestera_counter_stats_work); + schedule_delayed_work(&counter->stats_dw, COUNTER_POLL_TIME); + + return 0; +} + +void prestera_counter_fini(struct prestera_switch *sw) +{ + struct prestera_counter *counter = sw->counter; + u32 i; + + cancel_delayed_work_sync(&counter->stats_dw); + + for (i = 0; i < counter->block_list_len; i++) + WARN_ON(counter->block_list[i]); + + mutex_destroy(&counter->mtx); + kfree(counter->block_list); + kfree(counter); +} diff --git a/drivers/net/ethernet/marvell/prestera/prestera_counter.h b/drivers/net/ethernet/marvell/prestera/prestera_counter.h new file mode 100644 index 000000000000..ad6b73907799 --- /dev/null +++ b/drivers/net/ethernet/marvell/prestera/prestera_counter.h @@ -0,0 +1,30 @@ +/* SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0 */ +/* Copyright (c) 2021 Marvell International Ltd. All rights reserved. */ + +#ifndef _PRESTERA_COUNTER_H_ +#define _PRESTERA_COUNTER_H_ + +#include + +struct prestera_counter_stats { + u64 packets; + u64 bytes; +}; + +struct prestera_switch; +struct prestera_counter; +struct prestera_counter_block; + +int prestera_counter_init(struct prestera_switch *sw); +void prestera_counter_fini(struct prestera_switch *sw); + +int prestera_counter_get(struct prestera_counter *counter, u32 client, + struct prestera_counter_block **block, + u32 *counter_id); +void prestera_counter_put(struct prestera_counter *counter, + struct prestera_counter_block *block, u32 counter_id); +int prestera_counter_stats_get(struct prestera_counter *counter, + struct prestera_counter_block *block, + u32 counter_id, u64 *packets, u64 *bytes); + +#endif /* _PRESTERA_COUNTER_H_ */ diff --git a/drivers/net/ethernet/marvell/prestera/prestera_hw.c b/drivers/net/ethernet/marvell/prestera/prestera_hw.c index d6c425b651cb..92cb5e9099c6 100644 --- a/drivers/net/ethernet/marvell/prestera/prestera_hw.c +++ b/drivers/net/ethernet/marvell/prestera/prestera_hw.c @@ -9,6 +9,7 @@ #include "prestera.h" #include "prestera_hw.h" #include "prestera_acl.h" +#include "prestera_counter.h" #define PRESTERA_SWITCH_INIT_TIMEOUT_MS (30 * 1000) @@ -38,6 +39,13 @@ enum prestera_cmd_type_t { PRESTERA_CMD_TYPE_BRIDGE_PORT_ADD = 0x402, PRESTERA_CMD_TYPE_BRIDGE_PORT_DELETE = 0x403, + PRESTERA_CMD_TYPE_COUNTER_GET = 0x510, + PRESTERA_CMD_TYPE_COUNTER_ABORT = 0x511, + PRESTERA_CMD_TYPE_COUNTER_TRIGGER = 0x512, + PRESTERA_CMD_TYPE_COUNTER_BLOCK_GET = 0x513, + PRESTERA_CMD_TYPE_COUNTER_BLOCK_RELEASE = 0x514, + PRESTERA_CMD_TYPE_COUNTER_CLEAR = 0x515, + PRESTERA_CMD_TYPE_VTCAM_CREATE = 0x540, PRESTERA_CMD_TYPE_VTCAM_DESTROY = 0x541, PRESTERA_CMD_TYPE_VTCAM_RULE_ADD = 0x550, @@ -408,7 +416,34 @@ struct prestera_msg_vtcam_resp { struct prestera_msg_acl_action { __le32 id; - __le32 __reserved[7]; + __le32 __reserved; + union { + struct { + __le32 id; + } count; + __le32 reserved[6]; + }; +}; + +struct prestera_msg_counter_req { + struct prestera_msg_cmd cmd; + __le32 client; + __le32 block_id; + __le32 num_counters; +}; + +struct prestera_msg_counter_stats { + __le64 packets; + __le64 bytes; +}; + +struct prestera_msg_counter_resp { + struct prestera_msg_ret ret; + __le32 block_id; + __le32 offset; + __le32 num_counters; + __le32 done; + struct prestera_msg_counter_stats stats[0]; }; struct prestera_msg_span_req { @@ -512,6 +547,8 @@ static void prestera_hw_build_tests(void) BUILD_BUG_ON(sizeof(struct prestera_msg_vtcam_rule_del_req) != 12); BUILD_BUG_ON(sizeof(struct prestera_msg_vtcam_bind_req) != 20); BUILD_BUG_ON(sizeof(struct prestera_msg_acl_action) != 32); + BUILD_BUG_ON(sizeof(struct prestera_msg_counter_req) != 16); + BUILD_BUG_ON(sizeof(struct prestera_msg_counter_stats) != 16); /* check responses */ BUILD_BUG_ON(sizeof(struct prestera_msg_common_resp) != 8); @@ -523,6 +560,7 @@ static void prestera_hw_build_tests(void) BUILD_BUG_ON(sizeof(struct prestera_msg_span_resp) != 12); BUILD_BUG_ON(sizeof(struct prestera_msg_rxtx_resp) != 12); BUILD_BUG_ON(sizeof(struct prestera_msg_vtcam_resp) != 16); + BUILD_BUG_ON(sizeof(struct prestera_msg_counter_resp) != 24); /* check events */ BUILD_BUG_ON(sizeof(struct prestera_msg_event_port) != 20); @@ -1072,6 +1110,9 @@ prestera_acl_rule_add_put_action(struct prestera_msg_acl_action *action, case PRESTERA_ACL_RULE_ACTION_TRAP: /* just rule action id, no specific data */ break; + case PRESTERA_ACL_RULE_ACTION_COUNT: + action->count.id = __cpu_to_le32(info->count.id); + break; default: return -EINVAL; } @@ -1831,3 +1872,100 @@ void prestera_hw_event_handler_unregister(struct prestera_switch *sw, list_del_rcu(&eh->list); kfree_rcu(eh, rcu); } + +int prestera_hw_counter_trigger(struct prestera_switch *sw, u32 block_id) +{ + struct prestera_msg_counter_req req = { + .block_id = __cpu_to_le32(block_id) + }; + + return prestera_cmd(sw, PRESTERA_CMD_TYPE_COUNTER_TRIGGER, + &req.cmd, sizeof(req)); +} + +int prestera_hw_counter_abort(struct prestera_switch *sw) +{ + struct prestera_msg_counter_req req; + + return prestera_cmd(sw, PRESTERA_CMD_TYPE_COUNTER_ABORT, + &req.cmd, sizeof(req)); +} + +int prestera_hw_counters_get(struct prestera_switch *sw, u32 idx, + u32 *len, bool *done, + struct prestera_counter_stats *stats) +{ + struct prestera_msg_counter_resp *resp; + struct prestera_msg_counter_req req = { + .block_id = __cpu_to_le32(idx), + .num_counters = __cpu_to_le32(*len), + }; + size_t size = sizeof(*resp) + sizeof(*resp->stats) * (*len); + int err, i; + + resp = kmalloc(size, GFP_KERNEL); + if (!resp) + return -ENOMEM; + + err = prestera_cmd_ret(sw, PRESTERA_CMD_TYPE_COUNTER_GET, + &req.cmd, sizeof(req), &resp->ret, size); + if (err) + goto free_buff; + + for (i = 0; i < __le32_to_cpu(resp->num_counters); i++) { + stats[i].packets += __le64_to_cpu(resp->stats[i].packets); + stats[i].bytes += __le64_to_cpu(resp->stats[i].bytes); + } + + *len = __le32_to_cpu(resp->num_counters); + *done = __le32_to_cpu(resp->done); + +free_buff: + kfree(resp); + return err; +} + +int prestera_hw_counter_block_get(struct prestera_switch *sw, + u32 client, u32 *block_id, u32 *offset, + u32 *num_counters) +{ + struct prestera_msg_counter_resp resp; + struct prestera_msg_counter_req req = { + .client = __cpu_to_le32(client) + }; + int err; + + err = prestera_cmd_ret(sw, PRESTERA_CMD_TYPE_COUNTER_BLOCK_GET, + &req.cmd, sizeof(req), &resp.ret, sizeof(resp)); + if (err) + return err; + + *block_id = __le32_to_cpu(resp.block_id); + *offset = __le32_to_cpu(resp.offset); + *num_counters = __le32_to_cpu(resp.num_counters); + + return 0; +} + +int prestera_hw_counter_block_release(struct prestera_switch *sw, + u32 block_id) +{ + struct prestera_msg_counter_req req = { + .block_id = __cpu_to_le32(block_id) + }; + + return prestera_cmd(sw, PRESTERA_CMD_TYPE_COUNTER_BLOCK_RELEASE, + &req.cmd, sizeof(req)); +} + +int prestera_hw_counter_clear(struct prestera_switch *sw, u32 block_id, + u32 counter_id) +{ + struct prestera_msg_counter_req req = { + .block_id = __cpu_to_le32(block_id), + .num_counters = __cpu_to_le32(counter_id) + }; + + return prestera_cmd(sw, PRESTERA_CMD_TYPE_COUNTER_CLEAR, + &req.cmd, sizeof(req)); +} diff --git a/drivers/net/ethernet/marvell/prestera/prestera_hw.h b/drivers/net/ethernet/marvell/prestera/prestera_hw.h index 6b7a9f8e2ea2..0496e454e148 100644 --- a/drivers/net/ethernet/marvell/prestera/prestera_hw.h +++ b/drivers/net/ethernet/marvell/prestera/prestera_hw.h @@ -117,6 +117,12 @@ enum prestera_hw_vtcam_direction_t { PRESTERA_HW_VTCAM_DIR_EGRESS = 1, }; +enum { + PRESTERA_HW_COUNTER_CLIENT_LOOKUP_0 = 0, + PRESTERA_HW_COUNTER_CLIENT_LOOKUP_1 = 1, + PRESTERA_HW_COUNTER_CLIENT_LOOKUP_2 = 2, +}; + struct prestera_switch; struct prestera_port; struct prestera_port_stats; @@ -130,6 +136,7 @@ typedef void (*prestera_event_cb_t) struct prestera_rxtx_params; struct prestera_acl_hw_action_info; struct prestera_acl_iface; +struct prestera_counter_stats; /* Switch API */ int prestera_hw_switch_init(struct prestera_switch *sw); @@ -211,6 +218,20 @@ int prestera_hw_vtcam_iface_unbind(struct prestera_switch *sw, struct prestera_acl_iface *iface, u32 vtcam_id); +/* Counter API */ +int prestera_hw_counter_trigger(struct prestera_switch *sw, u32 block_id); +int prestera_hw_counter_abort(struct prestera_switch *sw); +int prestera_hw_counters_get(struct prestera_switch *sw, u32 idx, + u32 *len, bool *done, + struct prestera_counter_stats *stats); +int prestera_hw_counter_block_get(struct prestera_switch *sw, + u32 client, u32 *block_id, u32 *offset, + u32 *num_counters); +int prestera_hw_counter_block_release(struct prestera_switch *sw, + u32 block_id); +int prestera_hw_counter_clear(struct prestera_switch *sw, u32 block_id, + u32 counter_id); + /* SPAN API */ int prestera_hw_span_get(const struct prestera_port *port, u8 *span_id); int prestera_hw_span_bind(const struct prestera_port *port, u8 span_id); diff --git a/drivers/net/ethernet/marvell/prestera/prestera_main.c b/drivers/net/ethernet/marvell/prestera/prestera_main.c index 4369a3ffad45..a0dbad5cb88d 100644 --- a/drivers/net/ethernet/marvell/prestera/prestera_main.c +++ b/drivers/net/ethernet/marvell/prestera/prestera_main.c @@ -18,6 +18,7 @@ #include "prestera_rxtx.h" #include "prestera_devlink.h" #include "prestera_ethtool.h" +#include "prestera_counter.h" #include "prestera_switchdev.h" #define PRESTERA_MTU_DEFAULT 1536 @@ -904,6 +905,10 @@ static int prestera_switch_init(struct prestera_switch *sw) if (err) goto err_handlers_register; + err = prestera_counter_init(sw); + if (err) + goto err_counter_init; + err = prestera_acl_init(sw); if (err) goto err_acl_init; @@ -936,6 +941,8 @@ static int prestera_switch_init(struct prestera_switch *sw) err_span_init: prestera_acl_fini(sw); err_acl_init: + prestera_counter_fini(sw); +err_counter_init: prestera_event_handlers_unregister(sw); err_handlers_register: prestera_rxtx_switch_fini(sw); @@ -956,6 +963,7 @@ static void prestera_switch_fini(struct prestera_switch *sw) prestera_devlink_traps_unregister(sw); prestera_span_fini(sw); prestera_acl_fini(sw); + prestera_counter_fini(sw); prestera_event_handlers_unregister(sw); prestera_rxtx_switch_fini(sw); prestera_switchdev_fini(sw); From patchwork Tue Nov 23 16:58:02 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Volodymyr Mytnyk X-Patchwork-Id: 12634811 X-Patchwork-Delegate: kuba@kernel.org Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id D7E19C433FE for ; Tue, 23 Nov 2021 17:00:13 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S237926AbhKWRDU (ORCPT ); Tue, 23 Nov 2021 12:03:20 -0500 Received: from mail-eopbgr60121.outbound.protection.outlook.com ([40.107.6.121]:58175 "EHLO EUR04-DB3-obe.outbound.protection.outlook.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S238466AbhKWRDO (ORCPT ); Tue, 23 Nov 2021 12:03:14 -0500 ARC-Seal: i=1; a=rsa-sha256; s=arcselector9901; d=microsoft.com; cv=none; b=UvVuJ6fTDswpLZF2ztgM0Ot8UTiLd1+Gu17r3WT+Hxs06aOAlCMcjZVV6Foe8k8KgFWq9SuzUBnIzZY8WeKDVjhfEsPul0yF/W80TwOOvE4wXRvEGmXFGtFteh3Ef8Bf9YLIfSw5sjsCiXQkdQ/Lnof3D/JcINKEVgwg0aXoHOuVYaw+imcCtXAqMFJUeUlQWQaFYNaZPql9h04Yx3oQ+X2JMsgz8wtesnC4OBvFE7qWwZAslK6A7MAhLPaviYvx5hyBguO7JIR4Jden1eteFgaaUMHlK4ONKRYi7jssFNzmnwkPOCmKRVgR9ObK25DoH5qDeDupLFWclSRNJbX4Hg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=arcselector9901; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-AntiSpam-MessageData-ChunkCount:X-MS-Exchange-AntiSpam-MessageData-0:X-MS-Exchange-AntiSpam-MessageData-1; bh=nwQxo2Ki0/eqNgOWTaMngYYfpIjwMtXj5cF08J3rvQg=; b=YbTeaUPWCyvH0CNKj021dM87sou5wca+nYvhgoVX4FKKDiZFW8y2WuE0ccYORhEDOT/cPbNxcLXAouhAdqX3V9m6nZX35mpcdmv6QnAq5baay90ppP9c8zfzNFXVCJCAAlD/IrgzPqaZMA5QbeZ8YtwLo4yvZ3ZLgPc1CFR6dKvW6h0bAKcL8j4KIqgFH7KfUlB4De77XQej+Z/JDBOoynN6JPIJayjO2lInf7S7nim/yqhFIXWTYKpMMfToxE8LuwUQ2ctymGQ9xX2qrxOURijBNUf9IJou8P6gSGO/wtWx8Px/4+ISFuZuyhFjyAotzw39kJ2hqLQC4wtF0Cx6WQ== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=pass smtp.mailfrom=plvision.eu; dmarc=pass action=none header.from=plvision.eu; dkim=pass header.d=plvision.eu; arc=none DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=plvision.eu; s=selector2; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=nwQxo2Ki0/eqNgOWTaMngYYfpIjwMtXj5cF08J3rvQg=; b=uCSsUdQk7ZtyyXGLwlt/bPtFwXLwnfCdhOr9tSsAMcw00UsRhp6fXXtQX15kEI942jGJ7/q+B8CAorERxo1G44k1NWOQ24fIrwH1TiNcoN1gwMzBrqhsd9nOQ9QZCnDtkWMnW8lxbYN8MpMJ5e6qyq7o523hEhvSyeMwemI1UPw= Authentication-Results: dkim=none (message not signed) header.d=none;dmarc=none action=none header.from=plvision.eu; Received: from VI1P190MB0734.EURP190.PROD.OUTLOOK.COM (2603:10a6:800:123::23) by VE1P190MB0830.EURP190.PROD.OUTLOOK.COM (2603:10a6:800:1a9::5) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.4713.24; Tue, 23 Nov 2021 17:00:04 +0000 Received: from VI1P190MB0734.EURP190.PROD.OUTLOOK.COM ([fe80::e15a:32ff:b93c:d136]) by VI1P190MB0734.EURP190.PROD.OUTLOOK.COM ([fe80::e15a:32ff:b93c:d136%4]) with mapi id 15.20.4713.026; Tue, 23 Nov 2021 17:00:04 +0000 From: Volodymyr Mytnyk To: netdev@vger.kernel.org Cc: Taras Chornyi , Mickey Rachamim , Serhiy Pshyk , Volodymyr Mytnyk , Taras Chornyi , "David S. Miller" , Jakub Kicinski , linux-kernel@vger.kernel.org, Serhiy Boiko Subject: [PATCH net-next 3/3] net: prestera: acl: add rule stats support Date: Tue, 23 Nov 2021 18:58:02 +0200 Message-Id: <1637686684-2492-4-git-send-email-volodymyr.mytnyk@plvision.eu> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1637686684-2492-1-git-send-email-volodymyr.mytnyk@plvision.eu> References: <1637686684-2492-1-git-send-email-volodymyr.mytnyk@plvision.eu> X-ClientProxiedBy: AS8PR04CA0203.eurprd04.prod.outlook.com (2603:10a6:20b:2f3::28) To VI1P190MB0734.EURP190.PROD.OUTLOOK.COM (2603:10a6:800:123::23) MIME-Version: 1.0 Received: from vmytnykub.x.ow.s (217.20.186.93) by AS8PR04CA0203.eurprd04.prod.outlook.com (2603:10a6:20b:2f3::28) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256) id 15.20.4713.19 via Frontend Transport; Tue, 23 Nov 2021 17:00:03 +0000 X-MS-PublicTrafficType: Email X-MS-Office365-Filtering-Correlation-Id: d50097d5-66a2-4539-3f36-08d9aea2b1ef X-MS-TrafficTypeDiagnostic: VE1P190MB0830: X-Microsoft-Antispam-PRVS: X-MS-Oob-TLC-OOBClassifiers: OLM:374; X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0; X-Microsoft-Antispam-Message-Info: mDS8ovu5Tr6qU5LRPtU0qxMCmG+Sp7JNYyzgiuI26vpnV/mfBEEOgqqxVN+aXTCTgehdqpwaA6MugyanmibhmCAD//2wOyHkr4ih+UGRDw3eqr1sn6NBVhfg4h9+XZ86OtecUSe+RyTzdLSYtUGZxuzEoHQyMW57R8aViopp5CY6Tv6MkjqG8mEjwZUFilJdvweMqTftwzplRqd8s41KrQ5o7XyO+hnlnPFx6LWKv8Qpz117RBtSXKGhMCLjEIvjMPhxRotjvD3oCpBKz5x5pLyzRFhdINbur5U6BLBG62hkVCAMrEeR3ohTj5Bvqqg7DA+MF36iKbNfuHBt0cuOSsUrTkPJMYnowciE0Tp3w0Mwm9eB9JKT3taIy1EdgZFdmY/rIMDIpiqMtBwqTKsWCA5gzX0jC2IymoHdWAezeyXPoZ+R+OLg0teYwdTm8+Bqix8Vb2bpzjeHTgfYcHgVKQ3RrlJqpbQygwkCRJhAwo12267EoQFchgQA1Y7aoOSXA2oGJqphucvB10OJJ59+fLqZ4+u76Q6j61J6n5qSL/N4qH75AXTIOBqoQTL4jBPHA3JSYKlAyCiqcgYyfCQv9kE9QrgFpsK9RvIOTq21mwa0dX6+YKTvIs/E8hua6BheZq5Rb3JSc4laM1OQV70eniz5grFUTN/X7kiYs81pAUbi/GgliPztUvJrKUgojMIsfRzyiRVxrjoWK2Z8UwubHA== X-Forefront-Antispam-Report: CIP:255.255.255.255;CTRY:;LANG:en;SCL:1;SRV:;IPV:NLI;SFV:NSPM;H:VI1P190MB0734.EURP190.PROD.OUTLOOK.COM;PTR:;CAT:NONE;SFS:(136003)(376002)(39840400004)(366004)(396003)(346002)(36756003)(26005)(956004)(2616005)(83380400001)(66946007)(8936002)(8676002)(6512007)(38350700002)(66556008)(66476007)(52116002)(316002)(186003)(2906002)(6916009)(38100700002)(44832011)(86362001)(54906003)(4326008)(5660300002)(508600001)(6486002)(6506007);DIR:OUT;SFP:1102; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 1 X-MS-Exchange-AntiSpam-MessageData-0: A5ICtpKamxyZSkDE/MeqmVdSrfdPfkQmPdcQ2OWrf6oJ8IgmrGMuqq14IUZSrZKYXQNWaGJSKoI8NGu8Fl6vqZRKPldCj00mZwj72rAx+MUkQfrQlM7S0SM16GMdFy2enmuw2659HsZ+qHufXKAg08BBMNMnqPagYmtD4n0p/PYyyMzLMEFopOd7gexz0bWm/BDD5rhwqssAgQFzm7DOlQ1obMf2XdiU79FSKgOnFJhVl5N6AdXPCGqLEZU+Xlji7ljSll9w3/zHe8Wjg5v7goFp7NWH/rumilsSZcDa5xxpNIBu1vFXCS7VSDR7SY7cigjFeTK/UW37gTFwpYOhzf9DfRaoXj5FnpLt03oTXTCYqstsUQ4XqXP3Uw8Zy1EOIGYfMbn2waI1mJCU/zblqJGbxTq5JLcjdUtowwmOm0R2vMExMxCkWGigtfZhVE1oSZ/HlgNYVoa/aqfyWScEpLSdJ6IRaZ8++Ej+3LkdKE4HhvQKczLE/TP1nfAuE/fcSwkCTnYJdqVBsG1r8dJEs48/qGDn8ujjzT8nFTTTZxjnevn/2lBqy7LVb6J2CR8arpt5kwjooogXXgth8vvSver0FNCzsEgw2KYzoNURhybRiXFTFQ2SthAHALkjC7RD6HHhjdjcfJbDK/7WOVDXKkJzR3BF0YneNs+BxdTfNRdNoEasfbUZvMBZ9HARZexHxGemYFlQ9gJuQaEBOFsj2G+ewsG5ZEEBXhtN0A7qrbNRGi6tgPuZ/DyrpjqdxLRcnSO1kslycAZFI+6/bzN4AXZvI/h98YoSMChZL82MUZUKW4iY3rm6qrLudiDTbRjvkbr3BxVuialhrm3J3McE8P1a0lyq2vF2nvBXO2A5+zovuXa/XX/v7hucuXeLxGV2bkHsOr9GaVKGycm3BAILL9TRPlYmtgV6tl9M0NpiQ/2ogtznYHvqYlNjLGyYGGuZc53GTSHW7/qajKBcSvUqQR8hHnFVGoM8dsDrapoT3+/iDFLm8+DbdtshfpJRXcFTpSyoc1tZ9oGh3EGmWPg8Ps2QeGZP2kM2wrshNpUIqwCLLLRoH+6iCsNJnj10OhMFfe3Mhj2XtiEAwjWuuhBFjfwCXtqEYcTFZW6oG/8zKb+OPqdkAr2hryZbCDvs5nuw9MG9aLtbg9AU8OSQLeQ98neWsIzyHZWe5VHV5ycbDqJRw3NbvBa+Vo/Rbw8l9USjTG3LfMyO7gNn8uxeu79YC6kODSS3W+FVm4ZBQHVzH/s8yWXrY489GAmzvCvVcO5sIzE6MbQ6ziKHBi+u9aJu3OZ5g01FfIqC/QSfOmehGyAkNG9YSjIwE5uyfldTlfG5gyEoZ2D59w88KQQdPDFXIZ33dQpdAPYXQcg3RU2HXVgnJCyD5uAXKOMt+FkBgZVEz4ZLE0Mx5x7cqK7DOHFxuW5wGzd+iWHTpdC/AURB3AgzRT0UP0w3vcgH/wdhZa2U0yrJ5nYLkmD+CZYzCzthfX8NTJLFpY8OdCny+M4J5zOtMNEp5+8AVj5dsNzmftE0ogNOEezuqcvWVORIo2ykhmmKniK/vSnTI5EOBD1pOY4Cm77Dgt6eevMQcStbNKY4sklDWRCd78QqCmxrIFh38j+6ea3nK1/QUxb5o+jpeOsY52npQl6Bzpo9gzgxzL36CmeV4yLNeqZOvsaTClAiOA== X-OriginatorOrg: plvision.eu X-MS-Exchange-CrossTenant-Network-Message-Id: d50097d5-66a2-4539-3f36-08d9aea2b1ef X-MS-Exchange-CrossTenant-AuthSource: VI1P190MB0734.EURP190.PROD.OUTLOOK.COM X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 23 Nov 2021 17:00:04.4131 (UTC) X-MS-Exchange-CrossTenant-FromEntityHeader: Hosted X-MS-Exchange-CrossTenant-Id: 03707b74-30f3-46b6-a0e0-ff0a7438c9c4 X-MS-Exchange-CrossTenant-MailboxType: HOSTED X-MS-Exchange-CrossTenant-UserPrincipalName: ojEVNKeNy+ASMUhd4JUdwsgFXQEin9be8wM/Eez61WpVGMQ6xcHS24kxiTB4y+yux7IjIyX9cR+CUAZ1459T5uAjFu03uqcq5RvfoV/FfQ4= X-MS-Exchange-Transport-CrossTenantHeadersStamped: VE1P190MB0830 Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org X-Patchwork-Delegate: kuba@kernel.org From: Volodymyr Mytnyk Make flower to use counter API to get rule HW statistics. Co-developed-by: Serhiy Boiko Signed-off-by: Serhiy Boiko Signed-off-by: Volodymyr Mytnyk --- .../net/ethernet/marvell/prestera/prestera_acl.c | 46 ++++++++++++++++++++-- .../net/ethernet/marvell/prestera/prestera_acl.h | 5 +++ 2 files changed, 48 insertions(+), 3 deletions(-) diff --git a/drivers/net/ethernet/marvell/prestera/prestera_acl.c b/drivers/net/ethernet/marvell/prestera/prestera_acl.c index f0119d72427f..f8eb99967bbb 100644 --- a/drivers/net/ethernet/marvell/prestera/prestera_acl.c +++ b/drivers/net/ethernet/marvell/prestera/prestera_acl.c @@ -33,6 +33,10 @@ struct prestera_acl_rule_entry { struct { u8 valid:1; } accept, drop, trap; + struct { + u32 id; + struct prestera_counter_block *block; + } counter; }; }; @@ -358,6 +362,10 @@ int prestera_acl_rule_add(struct prestera_switch *sw, rule->re_arg.vtcam_id = ruleset->vtcam_id; rule->re_key.prio = rule->priority; + /* setup counter */ + rule->re_arg.count.valid = true; + rule->re_arg.count.client = PRESTERA_HW_COUNTER_CLIENT_LOOKUP_0; + rule->re = prestera_acl_rule_entry_find(sw->acl, &rule->re_key); err = WARN_ON(rule->re) ? -EEXIST : 0; if (err) @@ -412,9 +420,20 @@ int prestera_acl_rule_get_stats(struct prestera_acl *acl, struct prestera_acl_rule *rule, u64 *packets, u64 *bytes, u64 *last_use) { + u64 current_packets; + u64 current_bytes; + int err; + + err = prestera_counter_stats_get(acl->sw->counter, + rule->re->counter.block, + rule->re->counter.id, + ¤t_packets, ¤t_bytes); + if (err) + return err; + + *packets = current_packets; + *bytes = current_bytes; *last_use = jiffies; - *packets = 0; - *bytes = 0; return 0; } @@ -460,6 +479,12 @@ static int __prestera_acl_rule_entry2hw_add(struct prestera_switch *sw, act_hw[act_num].id = PRESTERA_ACL_RULE_ACTION_TRAP; act_num++; } + /* counter */ + if (e->counter.block) { + act_hw[act_num].id = PRESTERA_ACL_RULE_ACTION_COUNT; + act_hw[act_num].count.id = e->counter.id; + act_num++; + } return prestera_hw_vtcam_rule_add(sw, e->vtcam_id, e->key.prio, e->key.match.key, e->key.match.mask, @@ -470,7 +495,8 @@ static void __prestera_acl_rule_entry_act_destruct(struct prestera_switch *sw, struct prestera_acl_rule_entry *e) { - /* destroy action entry */ + /* counter */ + prestera_counter_put(sw->counter, e->counter.block, e->counter.id); } void prestera_acl_rule_entry_destroy(struct prestera_acl *acl, @@ -499,8 +525,22 @@ __prestera_acl_rule_entry_act_construct(struct prestera_switch *sw, e->drop.valid = arg->drop.valid; /* trap */ e->trap.valid = arg->trap.valid; + /* counter */ + if (arg->count.valid) { + int err; + + err = prestera_counter_get(sw->counter, arg->count.client, + &e->counter.block, + &e->counter.id); + if (err) + goto err_out; + } return 0; + +err_out: + __prestera_acl_rule_entry_act_destruct(sw, e); + return -EINVAL; } struct prestera_acl_rule_entry * diff --git a/drivers/net/ethernet/marvell/prestera/prestera_acl.h b/drivers/net/ethernet/marvell/prestera/prestera_acl.h index a1a99f026b87..f2a46816c003 100644 --- a/drivers/net/ethernet/marvell/prestera/prestera_acl.h +++ b/drivers/net/ethernet/marvell/prestera/prestera_acl.h @@ -5,6 +5,7 @@ #define _PRESTERA_ACL_H_ #include +#include "prestera_counter.h" #define PRESTERA_ACL_KEYMASK_PCL_ID 0x3FF #define PRESTERA_ACL_KEYMASK_PCL_ID_USER \ @@ -86,6 +87,10 @@ struct prestera_acl_rule_entry_arg { struct { u8 valid:1; } accept, drop, trap; + struct { + u8 valid:1; + u32 client; + } count; }; };