162306a36Sopenharmony_ci// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0 262306a36Sopenharmony_ci/* Copyright (c) 2022, NVIDIA CORPORATION & AFFILIATES. All rights reserved. */ 362306a36Sopenharmony_ci 462306a36Sopenharmony_ci#include <linux/refcount.h> 562306a36Sopenharmony_ci#include <linux/idr.h> 662306a36Sopenharmony_ci 762306a36Sopenharmony_ci#include "spectrum.h" 862306a36Sopenharmony_ci#include "reg.h" 962306a36Sopenharmony_ci 1062306a36Sopenharmony_cistruct mlxsw_sp_pgt { 1162306a36Sopenharmony_ci struct idr pgt_idr; 1262306a36Sopenharmony_ci u16 end_index; /* Exclusive. */ 1362306a36Sopenharmony_ci struct mutex lock; /* Protects PGT. */ 1462306a36Sopenharmony_ci bool smpe_index_valid; 1562306a36Sopenharmony_ci}; 1662306a36Sopenharmony_ci 1762306a36Sopenharmony_cistruct mlxsw_sp_pgt_entry { 1862306a36Sopenharmony_ci struct list_head ports_list; 1962306a36Sopenharmony_ci u16 index; 2062306a36Sopenharmony_ci u16 smpe_index; 2162306a36Sopenharmony_ci}; 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_cistruct mlxsw_sp_pgt_entry_port { 2462306a36Sopenharmony_ci struct list_head list; /* Member of 'ports_list'. */ 2562306a36Sopenharmony_ci u16 local_port; 2662306a36Sopenharmony_ci}; 2762306a36Sopenharmony_ci 2862306a36Sopenharmony_ciint mlxsw_sp_pgt_mid_alloc(struct mlxsw_sp *mlxsw_sp, u16 *p_mid) 2962306a36Sopenharmony_ci{ 3062306a36Sopenharmony_ci int index, err = 0; 3162306a36Sopenharmony_ci 3262306a36Sopenharmony_ci mutex_lock(&mlxsw_sp->pgt->lock); 3362306a36Sopenharmony_ci index = idr_alloc(&mlxsw_sp->pgt->pgt_idr, NULL, 0, 3462306a36Sopenharmony_ci mlxsw_sp->pgt->end_index, GFP_KERNEL); 3562306a36Sopenharmony_ci 3662306a36Sopenharmony_ci if (index < 0) { 3762306a36Sopenharmony_ci err = index; 3862306a36Sopenharmony_ci goto err_idr_alloc; 3962306a36Sopenharmony_ci } 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_ci *p_mid = index; 4262306a36Sopenharmony_ci mutex_unlock(&mlxsw_sp->pgt->lock); 4362306a36Sopenharmony_ci return 0; 4462306a36Sopenharmony_ci 4562306a36Sopenharmony_cierr_idr_alloc: 4662306a36Sopenharmony_ci mutex_unlock(&mlxsw_sp->pgt->lock); 4762306a36Sopenharmony_ci return err; 4862306a36Sopenharmony_ci} 4962306a36Sopenharmony_ci 5062306a36Sopenharmony_civoid mlxsw_sp_pgt_mid_free(struct mlxsw_sp *mlxsw_sp, u16 mid_base) 5162306a36Sopenharmony_ci{ 5262306a36Sopenharmony_ci mutex_lock(&mlxsw_sp->pgt->lock); 5362306a36Sopenharmony_ci WARN_ON(idr_remove(&mlxsw_sp->pgt->pgt_idr, mid_base)); 5462306a36Sopenharmony_ci mutex_unlock(&mlxsw_sp->pgt->lock); 5562306a36Sopenharmony_ci} 5662306a36Sopenharmony_ci 5762306a36Sopenharmony_ciint 5862306a36Sopenharmony_cimlxsw_sp_pgt_mid_alloc_range(struct mlxsw_sp *mlxsw_sp, u16 mid_base, u16 count) 5962306a36Sopenharmony_ci{ 6062306a36Sopenharmony_ci unsigned int idr_cursor; 6162306a36Sopenharmony_ci int i, err; 6262306a36Sopenharmony_ci 6362306a36Sopenharmony_ci mutex_lock(&mlxsw_sp->pgt->lock); 6462306a36Sopenharmony_ci 6562306a36Sopenharmony_ci /* This function is supposed to be called several times as part of 6662306a36Sopenharmony_ci * driver init, in specific order. Verify that the mid_index is the 6762306a36Sopenharmony_ci * first free index in the idr, to be able to free the indexes in case 6862306a36Sopenharmony_ci * of error. 6962306a36Sopenharmony_ci */ 7062306a36Sopenharmony_ci idr_cursor = idr_get_cursor(&mlxsw_sp->pgt->pgt_idr); 7162306a36Sopenharmony_ci if (WARN_ON(idr_cursor != mid_base)) { 7262306a36Sopenharmony_ci err = -EINVAL; 7362306a36Sopenharmony_ci goto err_idr_cursor; 7462306a36Sopenharmony_ci } 7562306a36Sopenharmony_ci 7662306a36Sopenharmony_ci for (i = 0; i < count; i++) { 7762306a36Sopenharmony_ci err = idr_alloc_cyclic(&mlxsw_sp->pgt->pgt_idr, NULL, 7862306a36Sopenharmony_ci mid_base, mid_base + count, GFP_KERNEL); 7962306a36Sopenharmony_ci if (err < 0) 8062306a36Sopenharmony_ci goto err_idr_alloc_cyclic; 8162306a36Sopenharmony_ci } 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_ci mutex_unlock(&mlxsw_sp->pgt->lock); 8462306a36Sopenharmony_ci return 0; 8562306a36Sopenharmony_ci 8662306a36Sopenharmony_cierr_idr_alloc_cyclic: 8762306a36Sopenharmony_ci for (i--; i >= 0; i--) 8862306a36Sopenharmony_ci idr_remove(&mlxsw_sp->pgt->pgt_idr, mid_base + i); 8962306a36Sopenharmony_cierr_idr_cursor: 9062306a36Sopenharmony_ci mutex_unlock(&mlxsw_sp->pgt->lock); 9162306a36Sopenharmony_ci return err; 9262306a36Sopenharmony_ci} 9362306a36Sopenharmony_ci 9462306a36Sopenharmony_civoid 9562306a36Sopenharmony_cimlxsw_sp_pgt_mid_free_range(struct mlxsw_sp *mlxsw_sp, u16 mid_base, u16 count) 9662306a36Sopenharmony_ci{ 9762306a36Sopenharmony_ci struct idr *pgt_idr = &mlxsw_sp->pgt->pgt_idr; 9862306a36Sopenharmony_ci int i; 9962306a36Sopenharmony_ci 10062306a36Sopenharmony_ci mutex_lock(&mlxsw_sp->pgt->lock); 10162306a36Sopenharmony_ci 10262306a36Sopenharmony_ci for (i = 0; i < count; i++) 10362306a36Sopenharmony_ci WARN_ON_ONCE(idr_remove(pgt_idr, mid_base + i)); 10462306a36Sopenharmony_ci 10562306a36Sopenharmony_ci mutex_unlock(&mlxsw_sp->pgt->lock); 10662306a36Sopenharmony_ci} 10762306a36Sopenharmony_ci 10862306a36Sopenharmony_cistatic struct mlxsw_sp_pgt_entry_port * 10962306a36Sopenharmony_cimlxsw_sp_pgt_entry_port_lookup(struct mlxsw_sp_pgt_entry *pgt_entry, 11062306a36Sopenharmony_ci u16 local_port) 11162306a36Sopenharmony_ci{ 11262306a36Sopenharmony_ci struct mlxsw_sp_pgt_entry_port *pgt_entry_port; 11362306a36Sopenharmony_ci 11462306a36Sopenharmony_ci list_for_each_entry(pgt_entry_port, &pgt_entry->ports_list, list) { 11562306a36Sopenharmony_ci if (pgt_entry_port->local_port == local_port) 11662306a36Sopenharmony_ci return pgt_entry_port; 11762306a36Sopenharmony_ci } 11862306a36Sopenharmony_ci 11962306a36Sopenharmony_ci return NULL; 12062306a36Sopenharmony_ci} 12162306a36Sopenharmony_ci 12262306a36Sopenharmony_cistatic struct mlxsw_sp_pgt_entry * 12362306a36Sopenharmony_cimlxsw_sp_pgt_entry_create(struct mlxsw_sp_pgt *pgt, u16 mid, u16 smpe) 12462306a36Sopenharmony_ci{ 12562306a36Sopenharmony_ci struct mlxsw_sp_pgt_entry *pgt_entry; 12662306a36Sopenharmony_ci void *ret; 12762306a36Sopenharmony_ci int err; 12862306a36Sopenharmony_ci 12962306a36Sopenharmony_ci pgt_entry = kzalloc(sizeof(*pgt_entry), GFP_KERNEL); 13062306a36Sopenharmony_ci if (!pgt_entry) 13162306a36Sopenharmony_ci return ERR_PTR(-ENOMEM); 13262306a36Sopenharmony_ci 13362306a36Sopenharmony_ci ret = idr_replace(&pgt->pgt_idr, pgt_entry, mid); 13462306a36Sopenharmony_ci if (IS_ERR(ret)) { 13562306a36Sopenharmony_ci err = PTR_ERR(ret); 13662306a36Sopenharmony_ci goto err_idr_replace; 13762306a36Sopenharmony_ci } 13862306a36Sopenharmony_ci 13962306a36Sopenharmony_ci INIT_LIST_HEAD(&pgt_entry->ports_list); 14062306a36Sopenharmony_ci pgt_entry->index = mid; 14162306a36Sopenharmony_ci pgt_entry->smpe_index = smpe; 14262306a36Sopenharmony_ci return pgt_entry; 14362306a36Sopenharmony_ci 14462306a36Sopenharmony_cierr_idr_replace: 14562306a36Sopenharmony_ci kfree(pgt_entry); 14662306a36Sopenharmony_ci return ERR_PTR(err); 14762306a36Sopenharmony_ci} 14862306a36Sopenharmony_ci 14962306a36Sopenharmony_cistatic void mlxsw_sp_pgt_entry_destroy(struct mlxsw_sp_pgt *pgt, 15062306a36Sopenharmony_ci struct mlxsw_sp_pgt_entry *pgt_entry) 15162306a36Sopenharmony_ci{ 15262306a36Sopenharmony_ci WARN_ON(!list_empty(&pgt_entry->ports_list)); 15362306a36Sopenharmony_ci 15462306a36Sopenharmony_ci pgt_entry = idr_replace(&pgt->pgt_idr, NULL, pgt_entry->index); 15562306a36Sopenharmony_ci if (WARN_ON(IS_ERR(pgt_entry))) 15662306a36Sopenharmony_ci return; 15762306a36Sopenharmony_ci 15862306a36Sopenharmony_ci kfree(pgt_entry); 15962306a36Sopenharmony_ci} 16062306a36Sopenharmony_ci 16162306a36Sopenharmony_cistatic struct mlxsw_sp_pgt_entry * 16262306a36Sopenharmony_cimlxsw_sp_pgt_entry_get(struct mlxsw_sp_pgt *pgt, u16 mid, u16 smpe) 16362306a36Sopenharmony_ci{ 16462306a36Sopenharmony_ci struct mlxsw_sp_pgt_entry *pgt_entry; 16562306a36Sopenharmony_ci 16662306a36Sopenharmony_ci pgt_entry = idr_find(&pgt->pgt_idr, mid); 16762306a36Sopenharmony_ci if (pgt_entry) 16862306a36Sopenharmony_ci return pgt_entry; 16962306a36Sopenharmony_ci 17062306a36Sopenharmony_ci return mlxsw_sp_pgt_entry_create(pgt, mid, smpe); 17162306a36Sopenharmony_ci} 17262306a36Sopenharmony_ci 17362306a36Sopenharmony_cistatic void mlxsw_sp_pgt_entry_put(struct mlxsw_sp_pgt *pgt, u16 mid) 17462306a36Sopenharmony_ci{ 17562306a36Sopenharmony_ci struct mlxsw_sp_pgt_entry *pgt_entry; 17662306a36Sopenharmony_ci 17762306a36Sopenharmony_ci pgt_entry = idr_find(&pgt->pgt_idr, mid); 17862306a36Sopenharmony_ci if (WARN_ON(!pgt_entry)) 17962306a36Sopenharmony_ci return; 18062306a36Sopenharmony_ci 18162306a36Sopenharmony_ci if (list_empty(&pgt_entry->ports_list)) 18262306a36Sopenharmony_ci mlxsw_sp_pgt_entry_destroy(pgt, pgt_entry); 18362306a36Sopenharmony_ci} 18462306a36Sopenharmony_ci 18562306a36Sopenharmony_cistatic void mlxsw_sp_pgt_smid2_port_set(char *smid2_pl, u16 local_port, 18662306a36Sopenharmony_ci bool member) 18762306a36Sopenharmony_ci{ 18862306a36Sopenharmony_ci mlxsw_reg_smid2_port_set(smid2_pl, local_port, member); 18962306a36Sopenharmony_ci mlxsw_reg_smid2_port_mask_set(smid2_pl, local_port, 1); 19062306a36Sopenharmony_ci} 19162306a36Sopenharmony_ci 19262306a36Sopenharmony_cistatic int 19362306a36Sopenharmony_cimlxsw_sp_pgt_entry_port_write(struct mlxsw_sp *mlxsw_sp, 19462306a36Sopenharmony_ci const struct mlxsw_sp_pgt_entry *pgt_entry, 19562306a36Sopenharmony_ci u16 local_port, bool member) 19662306a36Sopenharmony_ci{ 19762306a36Sopenharmony_ci char *smid2_pl; 19862306a36Sopenharmony_ci int err; 19962306a36Sopenharmony_ci 20062306a36Sopenharmony_ci smid2_pl = kmalloc(MLXSW_REG_SMID2_LEN, GFP_KERNEL); 20162306a36Sopenharmony_ci if (!smid2_pl) 20262306a36Sopenharmony_ci return -ENOMEM; 20362306a36Sopenharmony_ci 20462306a36Sopenharmony_ci mlxsw_reg_smid2_pack(smid2_pl, pgt_entry->index, 0, 0, 20562306a36Sopenharmony_ci mlxsw_sp->pgt->smpe_index_valid, 20662306a36Sopenharmony_ci pgt_entry->smpe_index); 20762306a36Sopenharmony_ci 20862306a36Sopenharmony_ci mlxsw_sp_pgt_smid2_port_set(smid2_pl, local_port, member); 20962306a36Sopenharmony_ci err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(smid2), smid2_pl); 21062306a36Sopenharmony_ci 21162306a36Sopenharmony_ci kfree(smid2_pl); 21262306a36Sopenharmony_ci 21362306a36Sopenharmony_ci return err; 21462306a36Sopenharmony_ci} 21562306a36Sopenharmony_ci 21662306a36Sopenharmony_cistatic struct mlxsw_sp_pgt_entry_port * 21762306a36Sopenharmony_cimlxsw_sp_pgt_entry_port_create(struct mlxsw_sp *mlxsw_sp, 21862306a36Sopenharmony_ci struct mlxsw_sp_pgt_entry *pgt_entry, 21962306a36Sopenharmony_ci u16 local_port) 22062306a36Sopenharmony_ci{ 22162306a36Sopenharmony_ci struct mlxsw_sp_pgt_entry_port *pgt_entry_port; 22262306a36Sopenharmony_ci int err; 22362306a36Sopenharmony_ci 22462306a36Sopenharmony_ci pgt_entry_port = kzalloc(sizeof(*pgt_entry_port), GFP_KERNEL); 22562306a36Sopenharmony_ci if (!pgt_entry_port) 22662306a36Sopenharmony_ci return ERR_PTR(-ENOMEM); 22762306a36Sopenharmony_ci 22862306a36Sopenharmony_ci err = mlxsw_sp_pgt_entry_port_write(mlxsw_sp, pgt_entry, local_port, 22962306a36Sopenharmony_ci true); 23062306a36Sopenharmony_ci if (err) 23162306a36Sopenharmony_ci goto err_pgt_entry_port_write; 23262306a36Sopenharmony_ci 23362306a36Sopenharmony_ci pgt_entry_port->local_port = local_port; 23462306a36Sopenharmony_ci list_add(&pgt_entry_port->list, &pgt_entry->ports_list); 23562306a36Sopenharmony_ci 23662306a36Sopenharmony_ci return pgt_entry_port; 23762306a36Sopenharmony_ci 23862306a36Sopenharmony_cierr_pgt_entry_port_write: 23962306a36Sopenharmony_ci kfree(pgt_entry_port); 24062306a36Sopenharmony_ci return ERR_PTR(err); 24162306a36Sopenharmony_ci} 24262306a36Sopenharmony_ci 24362306a36Sopenharmony_cistatic void 24462306a36Sopenharmony_cimlxsw_sp_pgt_entry_port_destroy(struct mlxsw_sp *mlxsw_sp, 24562306a36Sopenharmony_ci struct mlxsw_sp_pgt_entry *pgt_entry, 24662306a36Sopenharmony_ci struct mlxsw_sp_pgt_entry_port *pgt_entry_port) 24762306a36Sopenharmony_ci 24862306a36Sopenharmony_ci{ 24962306a36Sopenharmony_ci list_del(&pgt_entry_port->list); 25062306a36Sopenharmony_ci mlxsw_sp_pgt_entry_port_write(mlxsw_sp, pgt_entry, 25162306a36Sopenharmony_ci pgt_entry_port->local_port, false); 25262306a36Sopenharmony_ci kfree(pgt_entry_port); 25362306a36Sopenharmony_ci} 25462306a36Sopenharmony_ci 25562306a36Sopenharmony_cistatic int mlxsw_sp_pgt_entry_port_add(struct mlxsw_sp *mlxsw_sp, u16 mid, 25662306a36Sopenharmony_ci u16 smpe, u16 local_port) 25762306a36Sopenharmony_ci{ 25862306a36Sopenharmony_ci struct mlxsw_sp_pgt_entry_port *pgt_entry_port; 25962306a36Sopenharmony_ci struct mlxsw_sp_pgt_entry *pgt_entry; 26062306a36Sopenharmony_ci int err; 26162306a36Sopenharmony_ci 26262306a36Sopenharmony_ci mutex_lock(&mlxsw_sp->pgt->lock); 26362306a36Sopenharmony_ci 26462306a36Sopenharmony_ci pgt_entry = mlxsw_sp_pgt_entry_get(mlxsw_sp->pgt, mid, smpe); 26562306a36Sopenharmony_ci if (IS_ERR(pgt_entry)) { 26662306a36Sopenharmony_ci err = PTR_ERR(pgt_entry); 26762306a36Sopenharmony_ci goto err_pgt_entry_get; 26862306a36Sopenharmony_ci } 26962306a36Sopenharmony_ci 27062306a36Sopenharmony_ci pgt_entry_port = mlxsw_sp_pgt_entry_port_create(mlxsw_sp, pgt_entry, 27162306a36Sopenharmony_ci local_port); 27262306a36Sopenharmony_ci if (IS_ERR(pgt_entry_port)) { 27362306a36Sopenharmony_ci err = PTR_ERR(pgt_entry_port); 27462306a36Sopenharmony_ci goto err_pgt_entry_port_get; 27562306a36Sopenharmony_ci } 27662306a36Sopenharmony_ci 27762306a36Sopenharmony_ci mutex_unlock(&mlxsw_sp->pgt->lock); 27862306a36Sopenharmony_ci return 0; 27962306a36Sopenharmony_ci 28062306a36Sopenharmony_cierr_pgt_entry_port_get: 28162306a36Sopenharmony_ci mlxsw_sp_pgt_entry_put(mlxsw_sp->pgt, mid); 28262306a36Sopenharmony_cierr_pgt_entry_get: 28362306a36Sopenharmony_ci mutex_unlock(&mlxsw_sp->pgt->lock); 28462306a36Sopenharmony_ci return err; 28562306a36Sopenharmony_ci} 28662306a36Sopenharmony_ci 28762306a36Sopenharmony_cistatic void mlxsw_sp_pgt_entry_port_del(struct mlxsw_sp *mlxsw_sp, 28862306a36Sopenharmony_ci u16 mid, u16 smpe, u16 local_port) 28962306a36Sopenharmony_ci{ 29062306a36Sopenharmony_ci struct mlxsw_sp_pgt_entry_port *pgt_entry_port; 29162306a36Sopenharmony_ci struct mlxsw_sp_pgt_entry *pgt_entry; 29262306a36Sopenharmony_ci 29362306a36Sopenharmony_ci mutex_lock(&mlxsw_sp->pgt->lock); 29462306a36Sopenharmony_ci 29562306a36Sopenharmony_ci pgt_entry = idr_find(&mlxsw_sp->pgt->pgt_idr, mid); 29662306a36Sopenharmony_ci if (!pgt_entry) 29762306a36Sopenharmony_ci goto out; 29862306a36Sopenharmony_ci 29962306a36Sopenharmony_ci pgt_entry_port = mlxsw_sp_pgt_entry_port_lookup(pgt_entry, local_port); 30062306a36Sopenharmony_ci if (!pgt_entry_port) 30162306a36Sopenharmony_ci goto out; 30262306a36Sopenharmony_ci 30362306a36Sopenharmony_ci mlxsw_sp_pgt_entry_port_destroy(mlxsw_sp, pgt_entry, pgt_entry_port); 30462306a36Sopenharmony_ci mlxsw_sp_pgt_entry_put(mlxsw_sp->pgt, mid); 30562306a36Sopenharmony_ci 30662306a36Sopenharmony_ciout: 30762306a36Sopenharmony_ci mutex_unlock(&mlxsw_sp->pgt->lock); 30862306a36Sopenharmony_ci} 30962306a36Sopenharmony_ci 31062306a36Sopenharmony_ciint mlxsw_sp_pgt_entry_port_set(struct mlxsw_sp *mlxsw_sp, u16 mid, 31162306a36Sopenharmony_ci u16 smpe, u16 local_port, bool member) 31262306a36Sopenharmony_ci{ 31362306a36Sopenharmony_ci if (member) 31462306a36Sopenharmony_ci return mlxsw_sp_pgt_entry_port_add(mlxsw_sp, mid, smpe, 31562306a36Sopenharmony_ci local_port); 31662306a36Sopenharmony_ci 31762306a36Sopenharmony_ci mlxsw_sp_pgt_entry_port_del(mlxsw_sp, mid, smpe, local_port); 31862306a36Sopenharmony_ci return 0; 31962306a36Sopenharmony_ci} 32062306a36Sopenharmony_ci 32162306a36Sopenharmony_ciint mlxsw_sp_pgt_init(struct mlxsw_sp *mlxsw_sp) 32262306a36Sopenharmony_ci{ 32362306a36Sopenharmony_ci struct mlxsw_sp_pgt *pgt; 32462306a36Sopenharmony_ci 32562306a36Sopenharmony_ci if (!MLXSW_CORE_RES_VALID(mlxsw_sp->core, PGT_SIZE)) 32662306a36Sopenharmony_ci return -EIO; 32762306a36Sopenharmony_ci 32862306a36Sopenharmony_ci pgt = kzalloc(sizeof(*mlxsw_sp->pgt), GFP_KERNEL); 32962306a36Sopenharmony_ci if (!pgt) 33062306a36Sopenharmony_ci return -ENOMEM; 33162306a36Sopenharmony_ci 33262306a36Sopenharmony_ci idr_init(&pgt->pgt_idr); 33362306a36Sopenharmony_ci pgt->end_index = MLXSW_CORE_RES_GET(mlxsw_sp->core, PGT_SIZE); 33462306a36Sopenharmony_ci mutex_init(&pgt->lock); 33562306a36Sopenharmony_ci pgt->smpe_index_valid = mlxsw_sp->pgt_smpe_index_valid; 33662306a36Sopenharmony_ci mlxsw_sp->pgt = pgt; 33762306a36Sopenharmony_ci return 0; 33862306a36Sopenharmony_ci} 33962306a36Sopenharmony_ci 34062306a36Sopenharmony_civoid mlxsw_sp_pgt_fini(struct mlxsw_sp *mlxsw_sp) 34162306a36Sopenharmony_ci{ 34262306a36Sopenharmony_ci mutex_destroy(&mlxsw_sp->pgt->lock); 34362306a36Sopenharmony_ci WARN_ON(!idr_is_empty(&mlxsw_sp->pgt->pgt_idr)); 34462306a36Sopenharmony_ci idr_destroy(&mlxsw_sp->pgt->pgt_idr); 34562306a36Sopenharmony_ci kfree(mlxsw_sp->pgt); 34662306a36Sopenharmony_ci} 347