From patchwork Thu Feb 7 11:22:54 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ido Schimmel X-Patchwork-Id: 1037988 X-Patchwork-Delegate: davem@davemloft.net Return-Path: X-Original-To: patchwork-incoming-netdev@ozlabs.org Delivered-To: patchwork-incoming-netdev@ozlabs.org Authentication-Results: ozlabs.org; spf=none (mailfrom) smtp.mailfrom=vger.kernel.org (client-ip=209.132.180.67; helo=vger.kernel.org; envelope-from=netdev-owner@vger.kernel.org; receiver=) Authentication-Results: ozlabs.org; dmarc=pass (p=none dis=none) header.from=mellanox.com Authentication-Results: ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=Mellanox.com header.i=@Mellanox.com header.b="TYdB3T6N"; dkim-atps=neutral Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 43wGCf4FmQz9s3x for ; Thu, 7 Feb 2019 22:23:42 +1100 (AEDT) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727197AbfBGLXl (ORCPT ); Thu, 7 Feb 2019 06:23:41 -0500 Received: from mail-eopbgr30058.outbound.protection.outlook.com ([40.107.3.58]:15520 "EHLO EUR03-AM5-obe.outbound.protection.outlook.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S1726880AbfBGLXj (ORCPT ); Thu, 7 Feb 2019 06:23:39 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=Mellanox.com; s=selector1; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=AfFDlU3nGLUBYh3qw1TV4azbV/7Qsm3f13ti2kldcMw=; b=TYdB3T6Nw6wWjhEQ3TXUrmgD1yQRnzsNLLYBHMQZ+eYZdB/T549T539Oiy8yXpxYTSmD1hdE6G02Xg2KOyttaLHNM8WmbCmjLsFArbk4HvH5ISNMtGZhv0qLfcQeXfLBvVKdlaA2cRKbHU9LAKfpIqbdhkTZL+RxAbmPxnsg1yo= Received: from AM6PR05MB5240.eurprd05.prod.outlook.com (20.177.196.214) by AM6PR05MB5624.eurprd05.prod.outlook.com (20.178.86.25) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.1601.21; Thu, 7 Feb 2019 11:22:54 +0000 Received: from AM6PR05MB5240.eurprd05.prod.outlook.com ([fe80::3542:889c:3a85:3866]) by AM6PR05MB5240.eurprd05.prod.outlook.com ([fe80::3542:889c:3a85:3866%5]) with mapi id 15.20.1601.016; Thu, 7 Feb 2019 11:22:54 +0000 From: Ido Schimmel To: "netdev@vger.kernel.org" CC: "davem@davemloft.net" , Jiri Pirko , mlxsw , Ido Schimmel Subject: [PATCH net-next 11/14] mlxsw: spectrum_acl: Implement region migration according to hints Thread-Topic: [PATCH net-next 11/14] mlxsw: spectrum_acl: Implement region migration according to hints Thread-Index: AQHUvtd4a7+j30fpG0CHKaTaNcEUiw== Date: Thu, 7 Feb 2019 11:22:54 +0000 Message-ID: <20190207112211.10375-12-idosch@mellanox.com> References: <20190207112211.10375-1-idosch@mellanox.com> In-Reply-To: <20190207112211.10375-1-idosch@mellanox.com> Accept-Language: en-US Content-Language: en-US X-MS-Has-Attach: X-MS-TNEF-Correlator: x-clientproxiedby: AM6P194CA0032.EURP194.PROD.OUTLOOK.COM (2603:10a6:209:90::45) To AM6PR05MB5240.eurprd05.prod.outlook.com (2603:10a6:20b:64::22) authentication-results: spf=none (sender IP is ) smtp.mailfrom=idosch@mellanox.com; x-ms-exchange-messagesentrepresentingtype: 1 x-mailer: git-send-email 2.20.1 x-originating-ip: [193.47.165.251] x-ms-publictraffictype: Email x-microsoft-exchange-diagnostics: 1; AM6PR05MB5624; 6:0NQ07RGKjWgqkW1OGkDaE8zftuo36gnPzrU7umtReonW/1lqMLLapemc7sd/NypRifGTpt4yTh7uDkCMLj6hrRDRQnNsMTQieaMLAzBZLZMraoy2EXNdMydd+kduJblIL8ikeW5S59SCuqoOUYeraoIgEzTYMIfelIKpnb/thQgybZRHUOjoc99hUutnDPEMkK6MEcqTrWWUbVSuTlMTxkT5JdvDYmTsGjOVn6V77sgtboBK8tfHy5hJ6RmEai3JHb3SH/ok9d4KZcWNVaJUAsFkCP90CKMy6EEZbSPNbRTba+udTVnICfPylcaAQleEAjLsKLzbN6CMk6T9JgPXkviqX0Z7yeEoGmwo6Jv45dnuyqaY540xhnVRZQgUXpFDPldXIw1xw4OqVIhQGyUXReWyvJvZlQB1/lcf8hn4N8kIpmMCIEWn0Vf6k5LTwQ8HVHflHPH/gH9Y1Xu4BseWkw==; 5:YTKbriW02Gd+NyMuTZnNs7uf3REBRUCirPNE5OIzRRgTGMWgGr0S4HSqvaIUHbDGt0yRykT00nLHpbqGhJjToxwZ9Bx8CkCvrlTyi64FfdZ4s+tYHB9tm9j+L0x3ydm1ohoDpqemgqdQdR+0tnOOSiht0A4i47Sz7f8rFtX3/BzlQFvW6LWCwLKetPVuSxFwX6DR3tDH7xoLB1oFUMjE/A==; 7:yyig1gLaVx3vfgLSz+PJQVoyUIQztBA7vqQLM9kXYkUm0P8uB68XkA+lO3tVuo7qI84PbYwRposc5d+MKMamJ7/cKJrCK/KmT7txZeVbYqwDj3lICoi9E5muwYpjwjsNMgkJHLo44CfFwI0ssFwx/A== x-ms-office365-filtering-correlation-id: cbadbad1-5b3a-4777-b531-08d68cee9a5c x-ms-office365-filtering-ht: Tenant x-microsoft-antispam: BCL:0; PCL:0; RULEID:(2390118)(7020095)(4652040)(8989299)(4534185)(4627221)(201703031133081)(201702281549075)(8990200)(5600110)(711020)(4605077)(4618075)(2017052603328)(7153060)(7193020); SRVR:AM6PR05MB5624; x-ms-traffictypediagnostic: AM6PR05MB5624: x-microsoft-antispam-prvs: x-forefront-prvs: 0941B96580 x-forefront-antispam-report: SFV:NSPM; SFS:(10009020)(376002)(346002)(396003)(136003)(366004)(39860400002)(189003)(199004)(81166006)(81156014)(8676002)(68736007)(8936002)(66066001)(6916009)(105586002)(3846002)(6116002)(71200400001)(71190400001)(6506007)(386003)(1076003)(102836004)(2351001)(478600001)(36756003)(52116002)(30864003)(2501003)(14454004)(76176011)(106356001)(26005)(1730700003)(50226002)(305945005)(186003)(54906003)(4326008)(2616005)(6512007)(6486002)(7736002)(5024004)(53946003)(446003)(53936002)(107886003)(6436002)(256004)(14444005)(99286004)(11346002)(5640700003)(316002)(86362001)(476003)(2906002)(486006)(97736004)(25786009); DIR:OUT; SFP:1101; SCL:1; SRVR:AM6PR05MB5624; H:AM6PR05MB5240.eurprd05.prod.outlook.com; FPR:; SPF:None; LANG:en; PTR:InfoNoRecords; MX:1; A:1; received-spf: None (protection.outlook.com: mellanox.com does not designate permitted sender hosts) x-ms-exchange-senderadcheck: 1 x-microsoft-antispam-message-info: NJ3b9s5E2CYlB4mHbDJMQW5vVBTjfLVQ7MIkikqZJ6s8C1Z/AnxiQrdTnFjCYi8o3AsIbBGNEkna/PLNdGAJeHhrwFWh/+Eea66XTE3WwK/+nw37taJUOlMmsbNTSr3O6dDYiOJJ/OVJQZaZtndWUUyx5vGkO9wfLaBRbf/z5uSj05zTzGCnYTcCWBafIHNkF8UKKiqFbta7CiwKGEQjHfOEi3SWgj9IxbKpSOGvrMP9uR8kE2Vmin3W85kMdLwpKaYeXqueZnI4Nhpz1/gpiPRjeLB9KQLvfKVAmegWvTGRgGWcE6esN/lBUyFrg5lM+rHR+Bv7JPzmjulMNEKuTX0/aj9joBWvrX/+nHORXIp3DIZquqE+AatAbfb7+3Fyz++Mx/OFXa40/utHOAuhPcDtVQBcqHE4M4z7lMz8joE= MIME-Version: 1.0 X-OriginatorOrg: Mellanox.com X-MS-Exchange-CrossTenant-Network-Message-Id: cbadbad1-5b3a-4777-b531-08d68cee9a5c X-MS-Exchange-CrossTenant-originalarrivaltime: 07 Feb 2019 11:22:53.4902 (UTC) X-MS-Exchange-CrossTenant-fromentityheader: Hosted X-MS-Exchange-CrossTenant-mailboxtype: HOSTED X-MS-Exchange-CrossTenant-id: a652971c-7d2e-4d9b-a6a4-d149256f461b X-MS-Exchange-Transport-CrossTenantHeadersStamped: AM6PR05MB5624 Sender: netdev-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org From: Jiri Pirko If the hints are returned, the migration should be started. For that to happen, there is a need to create a second physical region in TCAM with new ERP set by passing the hints and then move chunk by chunk, entry by entry. During the transition, two lookups will occur. One in old region and another in new region. The highest priority rule will be chosen. In an unlikely case that the migration will fail and also rollback to original region will fail the vregion will become in bad state. Everything will work, only no future rehash will be possible. In a follow-up work, this can be resolved by trying to resume the rollback in delayed work and repair the vregion. Signed-off-by: Jiri Pirko Signed-off-by: Ido Schimmel --- .../mellanox/mlxsw/spectrum_acl_tcam.c | 287 ++++++++++++++++-- .../mellanox/mlxsw/spectrum_acl_tcam.h | 2 + 2 files changed, 268 insertions(+), 21 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_tcam.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_tcam.c index 12d202afa233..9239ff4e94c4 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_tcam.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_tcam.c @@ -23,6 +23,8 @@ size_t mlxsw_sp_acl_tcam_priv_size(struct mlxsw_sp *mlxsw_sp) return ops->priv_size; } +#define MLXSW_SP_ACL_TCAM_VREGION_REHASH_INTRVL_DFLT 5000 /* ms */ + int mlxsw_sp_acl_tcam_init(struct mlxsw_sp *mlxsw_sp, struct mlxsw_sp_acl_tcam *tcam) { @@ -33,6 +35,10 @@ int mlxsw_sp_acl_tcam_init(struct mlxsw_sp *mlxsw_sp, size_t alloc_size; int err; + tcam->vregion_rehash_intrvl = + MLXSW_SP_ACL_TCAM_VREGION_REHASH_INTRVL_DFLT; + INIT_LIST_HEAD(&tcam->vregion_list); + max_tcam_regions = MLXSW_CORE_RES_GET(mlxsw_sp->core, ACL_MAX_TCAM_REGIONS); max_regions = MLXSW_CORE_RES_GET(mlxsw_sp->core, ACL_MAX_REGIONS); @@ -165,24 +171,33 @@ struct mlxsw_sp_acl_tcam_group { struct mlxsw_sp_acl_tcam_vregion { struct mlxsw_sp_acl_tcam_region *region; + struct mlxsw_sp_acl_tcam_region *region2; /* Used during migration */ struct list_head list; /* Member of a TCAM group */ + struct list_head tlist; /* Member of a TCAM */ struct list_head vchunk_list; /* List of vchunks under this vregion */ struct mlxsw_sp_acl_tcam_group *group; struct mlxsw_afk_key_info *key_info; + struct mlxsw_sp_acl_tcam *tcam; + struct delayed_work rehash_dw; + struct mlxsw_sp *mlxsw_sp; + bool failed_rollback; /* Indicates failed rollback during migration */ }; struct mlxsw_sp_acl_tcam_vchunk; struct mlxsw_sp_acl_tcam_chunk { struct mlxsw_sp_acl_tcam_vchunk *vchunk; + struct mlxsw_sp_acl_tcam_region *region; unsigned long priv[0]; /* priv has to be always the last item */ }; struct mlxsw_sp_acl_tcam_vchunk { struct mlxsw_sp_acl_tcam_chunk *chunk; + struct mlxsw_sp_acl_tcam_chunk *chunk2; /* Used during migration */ struct list_head list; /* Member of a TCAM vregion */ struct rhash_head ht_node; /* Member of a chunk HT */ + struct list_head ventry_list; unsigned int priority; /* Priority within the vregion and group */ struct mlxsw_sp_acl_tcam_group *group; struct mlxsw_sp_acl_tcam_vregion *vregion; @@ -191,13 +206,16 @@ struct mlxsw_sp_acl_tcam_vchunk { struct mlxsw_sp_acl_tcam_entry { struct mlxsw_sp_acl_tcam_ventry *ventry; + struct mlxsw_sp_acl_tcam_chunk *chunk; unsigned long priv[0]; /* priv has to be always the last item */ }; struct mlxsw_sp_acl_tcam_ventry { struct mlxsw_sp_acl_tcam_entry *entry; + struct list_head list; /* Member of a TCAM vchunk */ struct mlxsw_sp_acl_tcam_vchunk *vchunk; + struct mlxsw_sp_acl_rule_info *rulei; }; static const struct rhashtable_params mlxsw_sp_acl_tcam_vchunk_ht_params = { @@ -215,9 +233,13 @@ static int mlxsw_sp_acl_tcam_group_update(struct mlxsw_sp *mlxsw_sp, int acl_index = 0; mlxsw_reg_pagt_pack(pagt_pl, group->id); - list_for_each_entry(vregion, &group->vregion_list, list) + list_for_each_entry(vregion, &group->vregion_list, list) { + if (vregion->region2) + mlxsw_reg_pagt_acl_id_pack(pagt_pl, acl_index++, + vregion->region2->id, true); mlxsw_reg_pagt_acl_id_pack(pagt_pl, acl_index++, vregion->region->id, false); + } mlxsw_reg_pagt_size_set(pagt_pl, acl_index); return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(pagt), pagt_pl); } @@ -391,6 +413,9 @@ mlxsw_sp_acl_tcam_group_vregion_detach(struct mlxsw_sp *mlxsw_sp, struct mlxsw_sp_acl_tcam_vregion *vregion) { list_del(&vregion->list); + if (vregion->region2) + mlxsw_sp_acl_tcam_group_region_detach(mlxsw_sp, + vregion->region2); mlxsw_sp_acl_tcam_group_region_detach(mlxsw_sp, vregion->region); } @@ -542,7 +567,8 @@ mlxsw_sp_acl_tcam_region_disable(struct mlxsw_sp *mlxsw_sp, static struct mlxsw_sp_acl_tcam_region * mlxsw_sp_acl_tcam_region_create(struct mlxsw_sp *mlxsw_sp, struct mlxsw_sp_acl_tcam *tcam, - struct mlxsw_sp_acl_tcam_vregion *vregion) + struct mlxsw_sp_acl_tcam_vregion *vregion, + void *hints_priv) { const struct mlxsw_sp_acl_tcam_ops *ops = mlxsw_sp->acl_tcam_ops; struct mlxsw_sp_acl_tcam_region *region; @@ -573,7 +599,7 @@ mlxsw_sp_acl_tcam_region_create(struct mlxsw_sp *mlxsw_sp, goto err_tcam_region_enable; err = ops->region_init(mlxsw_sp, region->priv, tcam->priv, - region, NULL); + region, hints_priv); if (err) goto err_tcam_region_init; @@ -605,11 +631,42 @@ mlxsw_sp_acl_tcam_region_destroy(struct mlxsw_sp *mlxsw_sp, kfree(region); } +static void +mlxsw_sp_acl_tcam_vregion_rehash_work_schedule(struct mlxsw_sp_acl_tcam_vregion *vregion) +{ + unsigned long interval = vregion->tcam->vregion_rehash_intrvl; + + if (!interval) + return; + mlxsw_core_schedule_dw(&vregion->rehash_dw, + msecs_to_jiffies(interval)); +} + +static int +mlxsw_sp_acl_tcam_vregion_rehash(struct mlxsw_sp *mlxsw_sp, + struct mlxsw_sp_acl_tcam_vregion *vregion); + +static void mlxsw_sp_acl_tcam_vregion_rehash_work(struct work_struct *work) +{ + struct mlxsw_sp_acl_tcam_vregion *vregion = + container_of(work, struct mlxsw_sp_acl_tcam_vregion, + rehash_dw.work); + + /* TODO: Take rtnl lock here as the rest of the code counts on it + * now. Later, this should be replaced by per-vregion lock. + */ + rtnl_lock(); + mlxsw_sp_acl_tcam_vregion_rehash(vregion->mlxsw_sp, vregion); + rtnl_unlock(); + mlxsw_sp_acl_tcam_vregion_rehash_work_schedule(vregion); +} + static struct mlxsw_sp_acl_tcam_vregion * mlxsw_sp_acl_tcam_vregion_create(struct mlxsw_sp *mlxsw_sp, struct mlxsw_sp_acl_tcam *tcam, struct mlxsw_afk_element_usage *elusage) { + const struct mlxsw_sp_acl_tcam_ops *ops = mlxsw_sp->acl_tcam_ops; struct mlxsw_afk *afk = mlxsw_sp_acl_afk(mlxsw_sp->acl); struct mlxsw_sp_acl_tcam_vregion *vregion; int err; @@ -618,6 +675,8 @@ mlxsw_sp_acl_tcam_vregion_create(struct mlxsw_sp *mlxsw_sp, if (!vregion) return ERR_PTR(-ENOMEM); INIT_LIST_HEAD(&vregion->vchunk_list); + vregion->tcam = tcam; + vregion->mlxsw_sp = mlxsw_sp; vregion->key_info = mlxsw_afk_key_info_get(afk, elusage); if (IS_ERR(vregion->key_info)) { @@ -626,12 +685,21 @@ mlxsw_sp_acl_tcam_vregion_create(struct mlxsw_sp *mlxsw_sp, } vregion->region = mlxsw_sp_acl_tcam_region_create(mlxsw_sp, tcam, - vregion); + vregion, NULL); if (IS_ERR(vregion->region)) { err = PTR_ERR(vregion->region); goto err_region_create; } + list_add_tail(&vregion->tlist, &tcam->vregion_list); + + if (ops->region_rehash_hints_get) { + /* Create the delayed work for vregion periodic rehash */ + INIT_DELAYED_WORK(&vregion->rehash_dw, + mlxsw_sp_acl_tcam_vregion_rehash_work); + mlxsw_sp_acl_tcam_vregion_rehash_work_schedule(vregion); + } + return vregion; err_region_create: @@ -645,6 +713,13 @@ static void mlxsw_sp_acl_tcam_vregion_destroy(struct mlxsw_sp *mlxsw_sp, struct mlxsw_sp_acl_tcam_vregion *vregion) { + const struct mlxsw_sp_acl_tcam_ops *ops = mlxsw_sp->acl_tcam_ops; + + if (ops->region_rehash_hints_get) + cancel_delayed_work_sync(&vregion->rehash_dw); + list_del(&vregion->tlist); + if (vregion->region2) + mlxsw_sp_acl_tcam_region_destroy(mlxsw_sp, vregion->region2); mlxsw_sp_acl_tcam_region_destroy(mlxsw_sp, vregion->region); mlxsw_afk_key_info_put(vregion->key_info); kfree(vregion); @@ -728,6 +803,7 @@ mlxsw_sp_acl_tcam_chunk_create(struct mlxsw_sp *mlxsw_sp, if (!chunk) return ERR_PTR(-ENOMEM); chunk->vchunk = vchunk; + chunk->region = region; ops->chunk_init(region->priv, chunk->priv, vchunk->priority); return chunk; @@ -758,6 +834,7 @@ mlxsw_sp_acl_tcam_vchunk_create(struct mlxsw_sp *mlxsw_sp, vchunk = kzalloc(sizeof(*vchunk), GFP_KERNEL); if (!vchunk) return ERR_PTR(-ENOMEM); + INIT_LIST_HEAD(&vchunk->ventry_list); vchunk->priority = priority; vchunk->group = group; vchunk->ref_count = 1; @@ -797,6 +874,8 @@ mlxsw_sp_acl_tcam_vchunk_destroy(struct mlxsw_sp *mlxsw_sp, { struct mlxsw_sp_acl_tcam_group *group = vchunk->group; + if (vchunk->chunk2) + mlxsw_sp_acl_tcam_chunk_destroy(mlxsw_sp, vchunk->chunk2); mlxsw_sp_acl_tcam_chunk_destroy(mlxsw_sp, vchunk->chunk); rhashtable_remove_fast(&group->vchunk_ht, &vchunk->ht_node, mlxsw_sp_acl_tcam_vchunk_ht_params); @@ -837,9 +916,7 @@ mlxsw_sp_acl_tcam_vchunk_put(struct mlxsw_sp *mlxsw_sp, static struct mlxsw_sp_acl_tcam_entry * mlxsw_sp_acl_tcam_entry_create(struct mlxsw_sp *mlxsw_sp, struct mlxsw_sp_acl_tcam_ventry *ventry, - struct mlxsw_sp_acl_tcam_region *region, - struct mlxsw_sp_acl_tcam_chunk *chunk, - struct mlxsw_sp_acl_rule_info *rulei) + struct mlxsw_sp_acl_tcam_chunk *chunk) { const struct mlxsw_sp_acl_tcam_ops *ops = mlxsw_sp->acl_tcam_ops; struct mlxsw_sp_acl_tcam_entry *entry; @@ -849,9 +926,10 @@ mlxsw_sp_acl_tcam_entry_create(struct mlxsw_sp *mlxsw_sp, if (!entry) return ERR_PTR(-ENOMEM); entry->ventry = ventry; + entry->chunk = chunk; - err = ops->entry_add(mlxsw_sp, region->priv, chunk->priv, - entry->priv, rulei); + err = ops->entry_add(mlxsw_sp, chunk->region->priv, chunk->priv, + entry->priv, ventry->rulei); if (err) goto err_entry_add; @@ -863,13 +941,12 @@ mlxsw_sp_acl_tcam_entry_create(struct mlxsw_sp *mlxsw_sp, } static void mlxsw_sp_acl_tcam_entry_destroy(struct mlxsw_sp *mlxsw_sp, - struct mlxsw_sp_acl_tcam_region *region, - struct mlxsw_sp_acl_tcam_chunk *chunk, struct mlxsw_sp_acl_tcam_entry *entry) { const struct mlxsw_sp_acl_tcam_ops *ops = mlxsw_sp->acl_tcam_ops; - ops->entry_del(mlxsw_sp, region->priv, chunk->priv, entry->priv); + ops->entry_del(mlxsw_sp, entry->chunk->region->priv, + entry->chunk->priv, entry->priv); kfree(entry); } @@ -887,13 +964,12 @@ mlxsw_sp_acl_tcam_entry_action_replace(struct mlxsw_sp *mlxsw_sp, static int mlxsw_sp_acl_tcam_entry_activity_get(struct mlxsw_sp *mlxsw_sp, - struct mlxsw_sp_acl_tcam_region *region, struct mlxsw_sp_acl_tcam_entry *entry, bool *activity) { const struct mlxsw_sp_acl_tcam_ops *ops = mlxsw_sp->acl_tcam_ops; - return ops->entry_activity_get(mlxsw_sp, region->priv, + return ops->entry_activity_get(mlxsw_sp, entry->chunk->region->priv, entry->priv, activity); } @@ -911,14 +987,16 @@ static int mlxsw_sp_acl_tcam_ventry_add(struct mlxsw_sp *mlxsw_sp, return PTR_ERR(vchunk); ventry->vchunk = vchunk; + ventry->rulei = rulei; ventry->entry = mlxsw_sp_acl_tcam_entry_create(mlxsw_sp, ventry, - vchunk->vregion->region, - vchunk->chunk, rulei); + vchunk->chunk); if (IS_ERR(ventry->entry)) { err = PTR_ERR(ventry->entry); goto err_entry_create; } + list_add_tail(&ventry->list, &vchunk->ventry_list); + return 0; err_entry_create: @@ -931,8 +1009,8 @@ static void mlxsw_sp_acl_tcam_ventry_del(struct mlxsw_sp *mlxsw_sp, { struct mlxsw_sp_acl_tcam_vchunk *vchunk = ventry->vchunk; - mlxsw_sp_acl_tcam_entry_destroy(mlxsw_sp, vchunk->vregion->region, - vchunk->chunk, ventry->entry); + list_del(&ventry->list); + mlxsw_sp_acl_tcam_entry_destroy(mlxsw_sp, ventry->entry); mlxsw_sp_acl_tcam_vchunk_put(mlxsw_sp, vchunk); } @@ -953,13 +1031,180 @@ mlxsw_sp_acl_tcam_ventry_activity_get(struct mlxsw_sp *mlxsw_sp, struct mlxsw_sp_acl_tcam_ventry *ventry, bool *activity) { - struct mlxsw_sp_acl_tcam_vchunk *vchunk = ventry->vchunk; - return mlxsw_sp_acl_tcam_entry_activity_get(mlxsw_sp, - vchunk->vregion->region, ventry->entry, activity); } +static int +mlxsw_sp_acl_tcam_ventry_migrate(struct mlxsw_sp *mlxsw_sp, + struct mlxsw_sp_acl_tcam_ventry *ventry, + struct mlxsw_sp_acl_tcam_chunk *chunk2) +{ + struct mlxsw_sp_acl_tcam_entry *entry2; + + entry2 = mlxsw_sp_acl_tcam_entry_create(mlxsw_sp, ventry, chunk2); + if (IS_ERR(entry2)) + return PTR_ERR(entry2); + mlxsw_sp_acl_tcam_entry_destroy(mlxsw_sp, ventry->entry); + ventry->entry = entry2; + return 0; +} + +static int +mlxsw_sp_acl_tcam_vchunk_migrate_one(struct mlxsw_sp *mlxsw_sp, + struct mlxsw_sp_acl_tcam_vchunk *vchunk, + struct mlxsw_sp_acl_tcam_region *region, + bool this_is_rollback) +{ + struct mlxsw_sp_acl_tcam_ventry *ventry; + struct mlxsw_sp_acl_tcam_chunk *chunk2; + int err; + int err2; + + chunk2 = mlxsw_sp_acl_tcam_chunk_create(mlxsw_sp, vchunk, region); + if (IS_ERR(chunk2)) { + if (this_is_rollback) + vchunk->vregion->failed_rollback = true; + return PTR_ERR(chunk2); + } + vchunk->chunk2 = chunk2; + list_for_each_entry(ventry, &vchunk->ventry_list, list) { + err = mlxsw_sp_acl_tcam_ventry_migrate(mlxsw_sp, ventry, + vchunk->chunk2); + if (err) { + if (this_is_rollback) { + vchunk->vregion->failed_rollback = true; + return err; + } + goto rollback; + } + } + mlxsw_sp_acl_tcam_chunk_destroy(mlxsw_sp, vchunk->chunk); + vchunk->chunk = chunk2; + vchunk->chunk2 = NULL; + return 0; + +rollback: + /* Migrate the entries back to the original chunk. If some entry + * migration fails, there's no good way how to proceed. Set the + * vregion with "failed_rollback" flag. + */ + list_for_each_entry_continue_reverse(ventry, &vchunk->ventry_list, + list) { + err2 = mlxsw_sp_acl_tcam_ventry_migrate(mlxsw_sp, ventry, + vchunk->chunk); + if (err2) { + vchunk->vregion->failed_rollback = true; + goto err_rollback; + } + } + + mlxsw_sp_acl_tcam_chunk_destroy(mlxsw_sp, vchunk->chunk2); + vchunk->chunk2 = NULL; + +err_rollback: + return err; +} + +static int +mlxsw_sp_acl_tcam_vchunk_migrate_all(struct mlxsw_sp *mlxsw_sp, + struct mlxsw_sp_acl_tcam_vregion *vregion) +{ + struct mlxsw_sp_acl_tcam_vchunk *vchunk; + int err; + + list_for_each_entry(vchunk, &vregion->vchunk_list, list) { + err = mlxsw_sp_acl_tcam_vchunk_migrate_one(mlxsw_sp, vchunk, + vregion->region2, + false); + if (err) + goto rollback; + } + return 0; + +rollback: + list_for_each_entry_continue_reverse(vchunk, &vregion->vchunk_list, + list) { + mlxsw_sp_acl_tcam_vchunk_migrate_one(mlxsw_sp, vchunk, + vregion->region, true); + } + return err; +} + +static int +mlxsw_sp_acl_tcam_vregion_migrate(struct mlxsw_sp *mlxsw_sp, + struct mlxsw_sp_acl_tcam_vregion *vregion, + void *hints_priv) +{ + struct mlxsw_sp_acl_tcam_region *region2, *unused_region; + int err; + + region2 = mlxsw_sp_acl_tcam_region_create(mlxsw_sp, vregion->tcam, + vregion, hints_priv); + if (IS_ERR(region2)) + return PTR_ERR(region2); + + vregion->region2 = region2; + err = mlxsw_sp_acl_tcam_group_region_attach(mlxsw_sp, region2); + if (err) + goto err_group_region_attach; + + err = mlxsw_sp_acl_tcam_vchunk_migrate_all(mlxsw_sp, vregion); + if (!vregion->failed_rollback) { + if (!err) { + /* In case of successful migration, region2 is used and + * the original is unused. + */ + unused_region = vregion->region; + vregion->region = vregion->region2; + } else { + /* In case of failure during migration, the original + * region is still used. + */ + unused_region = vregion->region2; + } + vregion->region2 = NULL; + mlxsw_sp_acl_tcam_group_region_detach(mlxsw_sp, unused_region); + mlxsw_sp_acl_tcam_region_destroy(mlxsw_sp, unused_region); + } + return err; + +err_group_region_attach: + vregion->region2 = NULL; + mlxsw_sp_acl_tcam_region_destroy(mlxsw_sp, region2); + return err; +} + +static int +mlxsw_sp_acl_tcam_vregion_rehash(struct mlxsw_sp *mlxsw_sp, + struct mlxsw_sp_acl_tcam_vregion *vregion) +{ + const struct mlxsw_sp_acl_tcam_ops *ops = mlxsw_sp->acl_tcam_ops; + void *hints_priv; + int err; + + if (vregion->failed_rollback) + return -EBUSY; + + hints_priv = ops->region_rehash_hints_get(vregion->region->priv); + if (IS_ERR(hints_priv)) { + err = PTR_ERR(hints_priv); + if (err != -EAGAIN) + dev_err(mlxsw_sp->bus_info->dev, "Failed get rehash hints\n"); + return err; + } + + err = mlxsw_sp_acl_tcam_vregion_migrate(mlxsw_sp, vregion, hints_priv); + if (err) { + dev_err(mlxsw_sp->bus_info->dev, "Failed to migrate vregion\n"); + if (vregion->failed_rollback) + dev_err(mlxsw_sp->bus_info->dev, "Failed to rollback during vregion migration fail\n"); + } + + ops->region_rehash_hints_put(hints_priv); + return err; +} + static const enum mlxsw_afk_element mlxsw_sp_acl_tcam_pattern_ipv4[] = { MLXSW_AFK_ELEMENT_SRC_SYS_PORT, MLXSW_AFK_ELEMENT_DMAC_32_47, diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_tcam.h b/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_tcam.h index c2a340270982..440a3483ed7b 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_tcam.h +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_tcam.h @@ -17,6 +17,8 @@ struct mlxsw_sp_acl_tcam { unsigned long *used_groups; /* bit array */ unsigned int max_groups; unsigned int max_group_size; + struct list_head vregion_list; + u32 vregion_rehash_intrvl; /* ms */ unsigned long priv[0]; /* priv has to be always the last item */ };