19948a064SJiri Pirko // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
29948a064SJiri Pirko /* Copyright (c) 2017-2018 Mellanox Technologies. All rights reserved */
3ff7b0d27SArkadi Sharshevsky
4ff7b0d27SArkadi Sharshevsky #include <linux/kernel.h>
5ff7b0d27SArkadi Sharshevsky #include <linux/bitops.h>
66c5a688eSIdo Schimmel #include <linux/spinlock.h>
7ff7b0d27SArkadi Sharshevsky
8ff7b0d27SArkadi Sharshevsky #include "spectrum_cnt.h"
9ff7b0d27SArkadi Sharshevsky
10ff7b0d27SArkadi Sharshevsky struct mlxsw_sp_counter_sub_pool {
11d53cdbb8SJiri Pirko u64 size;
12ff7b0d27SArkadi Sharshevsky unsigned int base_index;
13b2d3e33cSJiri Pirko enum mlxsw_res_id entry_size_res_id;
14d53cdbb8SJiri Pirko const char *resource_name; /* devlink resource name */
15d53cdbb8SJiri Pirko u64 resource_id; /* devlink resource id */
16ff7b0d27SArkadi Sharshevsky unsigned int entry_size;
17ff7b0d27SArkadi Sharshevsky unsigned int bank_count;
184e145fc6SJiri Pirko atomic_t active_entries_count;
19ff7b0d27SArkadi Sharshevsky };
20ff7b0d27SArkadi Sharshevsky
21ff7b0d27SArkadi Sharshevsky struct mlxsw_sp_counter_pool {
22d53cdbb8SJiri Pirko u64 pool_size;
23ff7b0d27SArkadi Sharshevsky unsigned long *usage; /* Usage bitmap */
246c5a688eSIdo Schimmel spinlock_t counter_pool_lock; /* Protects counter pool allocations */
254e145fc6SJiri Pirko atomic_t active_entries_count;
26c33fbe94SJiri Pirko unsigned int sub_pools_count;
27c33fbe94SJiri Pirko struct mlxsw_sp_counter_sub_pool sub_pools[];
28ff7b0d27SArkadi Sharshevsky };
29ff7b0d27SArkadi Sharshevsky
30c33fbe94SJiri Pirko static const struct mlxsw_sp_counter_sub_pool mlxsw_sp_counter_sub_pools[] = {
311abcbcc2SArkadi Sharshevsky [MLXSW_SP_COUNTER_SUB_POOL_FLOW] = {
32b2d3e33cSJiri Pirko .entry_size_res_id = MLXSW_RES_ID_COUNTER_SIZE_PACKETS_BYTES,
33d53cdbb8SJiri Pirko .resource_name = MLXSW_SP_RESOURCE_NAME_COUNTERS_FLOW,
34d53cdbb8SJiri Pirko .resource_id = MLXSW_SP_RESOURCE_COUNTERS_FLOW,
351abcbcc2SArkadi Sharshevsky .bank_count = 6,
361abcbcc2SArkadi Sharshevsky },
37e0c0afd8SArkadi Sharshevsky [MLXSW_SP_COUNTER_SUB_POOL_RIF] = {
38b2d3e33cSJiri Pirko .entry_size_res_id = MLXSW_RES_ID_COUNTER_SIZE_ROUTER_BASIC,
39d53cdbb8SJiri Pirko .resource_name = MLXSW_SP_RESOURCE_NAME_COUNTERS_RIF,
40d53cdbb8SJiri Pirko .resource_id = MLXSW_SP_RESOURCE_COUNTERS_RIF,
41e0c0afd8SArkadi Sharshevsky .bank_count = 2,
42e0c0afd8SArkadi Sharshevsky }
431abcbcc2SArkadi Sharshevsky };
44ff7b0d27SArkadi Sharshevsky
mlxsw_sp_counter_sub_pool_occ_get(void * priv)454e145fc6SJiri Pirko static u64 mlxsw_sp_counter_sub_pool_occ_get(void *priv)
464e145fc6SJiri Pirko {
474e145fc6SJiri Pirko const struct mlxsw_sp_counter_sub_pool *sub_pool = priv;
484e145fc6SJiri Pirko
494e145fc6SJiri Pirko return atomic_read(&sub_pool->active_entries_count);
504e145fc6SJiri Pirko }
514e145fc6SJiri Pirko
mlxsw_sp_counter_sub_pools_init(struct mlxsw_sp * mlxsw_sp)5253d96366SJiri Pirko static int mlxsw_sp_counter_sub_pools_init(struct mlxsw_sp *mlxsw_sp)
531abcbcc2SArkadi Sharshevsky {
54c33fbe94SJiri Pirko struct mlxsw_sp_counter_pool *pool = mlxsw_sp->counter_pool;
5553d96366SJiri Pirko struct devlink *devlink = priv_to_devlink(mlxsw_sp->core);
561abcbcc2SArkadi Sharshevsky struct mlxsw_sp_counter_sub_pool *sub_pool;
5753d96366SJiri Pirko unsigned int base_index = 0;
58b2d3e33cSJiri Pirko enum mlxsw_res_id res_id;
5953d96366SJiri Pirko int err;
60b2d3e33cSJiri Pirko int i;
611abcbcc2SArkadi Sharshevsky
62b2d3e33cSJiri Pirko for (i = 0; i < pool->sub_pools_count; i++) {
63b2d3e33cSJiri Pirko sub_pool = &pool->sub_pools[i];
64b2d3e33cSJiri Pirko res_id = sub_pool->entry_size_res_id;
65b2d3e33cSJiri Pirko
66b2d3e33cSJiri Pirko if (!mlxsw_core_res_valid(mlxsw_sp->core, res_id))
671abcbcc2SArkadi Sharshevsky return -EIO;
68b2d3e33cSJiri Pirko sub_pool->entry_size = mlxsw_core_res_get(mlxsw_sp->core,
69b2d3e33cSJiri Pirko res_id);
70*72a4c8c9SJiri Pirko err = devl_resource_size_get(devlink,
7153d96366SJiri Pirko sub_pool->resource_id,
7253d96366SJiri Pirko &sub_pool->size);
7353d96366SJiri Pirko if (err)
744e145fc6SJiri Pirko goto err_resource_size_get;
754e145fc6SJiri Pirko
76*72a4c8c9SJiri Pirko devl_resource_occ_get_register(devlink,
774e145fc6SJiri Pirko sub_pool->resource_id,
784e145fc6SJiri Pirko mlxsw_sp_counter_sub_pool_occ_get,
794e145fc6SJiri Pirko sub_pool);
8053d96366SJiri Pirko
8153d96366SJiri Pirko sub_pool->base_index = base_index;
8253d96366SJiri Pirko base_index += sub_pool->size;
834e145fc6SJiri Pirko atomic_set(&sub_pool->active_entries_count, 0);
84b2d3e33cSJiri Pirko }
851abcbcc2SArkadi Sharshevsky return 0;
864e145fc6SJiri Pirko
874e145fc6SJiri Pirko err_resource_size_get:
884e145fc6SJiri Pirko for (i--; i >= 0; i--) {
894e145fc6SJiri Pirko sub_pool = &pool->sub_pools[i];
904e145fc6SJiri Pirko
91*72a4c8c9SJiri Pirko devl_resource_occ_get_unregister(devlink,
924e145fc6SJiri Pirko sub_pool->resource_id);
934e145fc6SJiri Pirko }
944e145fc6SJiri Pirko return err;
954e145fc6SJiri Pirko }
964e145fc6SJiri Pirko
mlxsw_sp_counter_sub_pools_fini(struct mlxsw_sp * mlxsw_sp)974e145fc6SJiri Pirko static void mlxsw_sp_counter_sub_pools_fini(struct mlxsw_sp *mlxsw_sp)
984e145fc6SJiri Pirko {
994e145fc6SJiri Pirko struct mlxsw_sp_counter_pool *pool = mlxsw_sp->counter_pool;
1004e145fc6SJiri Pirko struct devlink *devlink = priv_to_devlink(mlxsw_sp->core);
1014e145fc6SJiri Pirko struct mlxsw_sp_counter_sub_pool *sub_pool;
1024e145fc6SJiri Pirko int i;
1034e145fc6SJiri Pirko
1044e145fc6SJiri Pirko for (i = 0; i < pool->sub_pools_count; i++) {
1054e145fc6SJiri Pirko sub_pool = &pool->sub_pools[i];
1064e145fc6SJiri Pirko
1074e145fc6SJiri Pirko WARN_ON(atomic_read(&sub_pool->active_entries_count));
108*72a4c8c9SJiri Pirko devl_resource_occ_get_unregister(devlink,
1094e145fc6SJiri Pirko sub_pool->resource_id);
1104e145fc6SJiri Pirko }
1114e145fc6SJiri Pirko }
1124e145fc6SJiri Pirko
mlxsw_sp_counter_pool_occ_get(void * priv)1134e145fc6SJiri Pirko static u64 mlxsw_sp_counter_pool_occ_get(void *priv)
1144e145fc6SJiri Pirko {
1154e145fc6SJiri Pirko const struct mlxsw_sp_counter_pool *pool = priv;
1164e145fc6SJiri Pirko
1174e145fc6SJiri Pirko return atomic_read(&pool->active_entries_count);
1181abcbcc2SArkadi Sharshevsky }
1191abcbcc2SArkadi Sharshevsky
mlxsw_sp_counter_pool_init(struct mlxsw_sp * mlxsw_sp)120ff7b0d27SArkadi Sharshevsky int mlxsw_sp_counter_pool_init(struct mlxsw_sp *mlxsw_sp)
121ff7b0d27SArkadi Sharshevsky {
122c33fbe94SJiri Pirko unsigned int sub_pools_count = ARRAY_SIZE(mlxsw_sp_counter_sub_pools);
123d53cdbb8SJiri Pirko struct devlink *devlink = priv_to_devlink(mlxsw_sp->core);
124ff7b0d27SArkadi Sharshevsky struct mlxsw_sp_counter_pool *pool;
125ff7b0d27SArkadi Sharshevsky int err;
126ff7b0d27SArkadi Sharshevsky
127c33fbe94SJiri Pirko pool = kzalloc(struct_size(pool, sub_pools, sub_pools_count),
128c33fbe94SJiri Pirko GFP_KERNEL);
129c33fbe94SJiri Pirko if (!pool)
130c33fbe94SJiri Pirko return -ENOMEM;
131c33fbe94SJiri Pirko mlxsw_sp->counter_pool = pool;
132c33fbe94SJiri Pirko pool->sub_pools_count = sub_pools_count;
13310470c0dSGustavo A. R. Silva memcpy(pool->sub_pools, mlxsw_sp_counter_sub_pools,
13410470c0dSGustavo A. R. Silva flex_array_size(pool, sub_pools, pool->sub_pools_count));
135c33fbe94SJiri Pirko spin_lock_init(&pool->counter_pool_lock);
1364e145fc6SJiri Pirko atomic_set(&pool->active_entries_count, 0);
137c33fbe94SJiri Pirko
138*72a4c8c9SJiri Pirko err = devl_resource_size_get(devlink, MLXSW_SP_RESOURCE_COUNTERS,
139d53cdbb8SJiri Pirko &pool->pool_size);
140d53cdbb8SJiri Pirko if (err)
141d53cdbb8SJiri Pirko goto err_pool_resource_size_get;
142*72a4c8c9SJiri Pirko devl_resource_occ_get_register(devlink, MLXSW_SP_RESOURCE_COUNTERS,
1434e145fc6SJiri Pirko mlxsw_sp_counter_pool_occ_get, pool);
144ff7b0d27SArkadi Sharshevsky
1452c087dfcSChristophe JAILLET pool->usage = bitmap_zalloc(pool->pool_size, GFP_KERNEL);
146ff7b0d27SArkadi Sharshevsky if (!pool->usage) {
147ff7b0d27SArkadi Sharshevsky err = -ENOMEM;
148ff7b0d27SArkadi Sharshevsky goto err_usage_alloc;
149ff7b0d27SArkadi Sharshevsky }
150ff7b0d27SArkadi Sharshevsky
15153d96366SJiri Pirko err = mlxsw_sp_counter_sub_pools_init(mlxsw_sp);
152d53cdbb8SJiri Pirko if (err)
15353d96366SJiri Pirko goto err_sub_pools_init;
154ff7b0d27SArkadi Sharshevsky
155ff7b0d27SArkadi Sharshevsky return 0;
156ff7b0d27SArkadi Sharshevsky
15753d96366SJiri Pirko err_sub_pools_init:
1582c087dfcSChristophe JAILLET bitmap_free(pool->usage);
159ff7b0d27SArkadi Sharshevsky err_usage_alloc:
160*72a4c8c9SJiri Pirko devl_resource_occ_get_unregister(devlink,
1614e145fc6SJiri Pirko MLXSW_SP_RESOURCE_COUNTERS);
162d53cdbb8SJiri Pirko err_pool_resource_size_get:
163ff7b0d27SArkadi Sharshevsky kfree(pool);
164ff7b0d27SArkadi Sharshevsky return err;
165ff7b0d27SArkadi Sharshevsky }
166ff7b0d27SArkadi Sharshevsky
mlxsw_sp_counter_pool_fini(struct mlxsw_sp * mlxsw_sp)167ff7b0d27SArkadi Sharshevsky void mlxsw_sp_counter_pool_fini(struct mlxsw_sp *mlxsw_sp)
168ff7b0d27SArkadi Sharshevsky {
169ff7b0d27SArkadi Sharshevsky struct mlxsw_sp_counter_pool *pool = mlxsw_sp->counter_pool;
1704e145fc6SJiri Pirko struct devlink *devlink = priv_to_devlink(mlxsw_sp->core);
171ff7b0d27SArkadi Sharshevsky
1724e145fc6SJiri Pirko mlxsw_sp_counter_sub_pools_fini(mlxsw_sp);
173ff7b0d27SArkadi Sharshevsky WARN_ON(find_first_bit(pool->usage, pool->pool_size) !=
174ff7b0d27SArkadi Sharshevsky pool->pool_size);
1754e145fc6SJiri Pirko WARN_ON(atomic_read(&pool->active_entries_count));
1762c087dfcSChristophe JAILLET bitmap_free(pool->usage);
177*72a4c8c9SJiri Pirko devl_resource_occ_get_unregister(devlink,
1784e145fc6SJiri Pirko MLXSW_SP_RESOURCE_COUNTERS);
179ff7b0d27SArkadi Sharshevsky kfree(pool);
180ff7b0d27SArkadi Sharshevsky }
181ff7b0d27SArkadi Sharshevsky
mlxsw_sp_counter_alloc(struct mlxsw_sp * mlxsw_sp,enum mlxsw_sp_counter_sub_pool_id sub_pool_id,unsigned int * p_counter_index)182ff7b0d27SArkadi Sharshevsky int mlxsw_sp_counter_alloc(struct mlxsw_sp *mlxsw_sp,
183ff7b0d27SArkadi Sharshevsky enum mlxsw_sp_counter_sub_pool_id sub_pool_id,
184ff7b0d27SArkadi Sharshevsky unsigned int *p_counter_index)
185ff7b0d27SArkadi Sharshevsky {
186ff7b0d27SArkadi Sharshevsky struct mlxsw_sp_counter_pool *pool = mlxsw_sp->counter_pool;
187ff7b0d27SArkadi Sharshevsky struct mlxsw_sp_counter_sub_pool *sub_pool;
188ff7b0d27SArkadi Sharshevsky unsigned int entry_index;
189ff7b0d27SArkadi Sharshevsky unsigned int stop_index;
1906c5a688eSIdo Schimmel int i, err;
191ff7b0d27SArkadi Sharshevsky
192c33fbe94SJiri Pirko sub_pool = &pool->sub_pools[sub_pool_id];
193ff7b0d27SArkadi Sharshevsky stop_index = sub_pool->base_index + sub_pool->size;
194ff7b0d27SArkadi Sharshevsky entry_index = sub_pool->base_index;
195ff7b0d27SArkadi Sharshevsky
1966c5a688eSIdo Schimmel spin_lock(&pool->counter_pool_lock);
197ff7b0d27SArkadi Sharshevsky entry_index = find_next_zero_bit(pool->usage, stop_index, entry_index);
1986c5a688eSIdo Schimmel if (entry_index == stop_index) {
1996c5a688eSIdo Schimmel err = -ENOBUFS;
2006c5a688eSIdo Schimmel goto err_alloc;
2016c5a688eSIdo Schimmel }
202ff7b0d27SArkadi Sharshevsky /* The sub-pools can contain non-integer number of entries
203ff7b0d27SArkadi Sharshevsky * so we must check for overflow
204ff7b0d27SArkadi Sharshevsky */
2056c5a688eSIdo Schimmel if (entry_index + sub_pool->entry_size > stop_index) {
2066c5a688eSIdo Schimmel err = -ENOBUFS;
2076c5a688eSIdo Schimmel goto err_alloc;
2086c5a688eSIdo Schimmel }
209ff7b0d27SArkadi Sharshevsky for (i = 0; i < sub_pool->entry_size; i++)
210ff7b0d27SArkadi Sharshevsky __set_bit(entry_index + i, pool->usage);
2116c5a688eSIdo Schimmel spin_unlock(&pool->counter_pool_lock);
212ff7b0d27SArkadi Sharshevsky
213ff7b0d27SArkadi Sharshevsky *p_counter_index = entry_index;
2144e145fc6SJiri Pirko atomic_add(sub_pool->entry_size, &sub_pool->active_entries_count);
2154e145fc6SJiri Pirko atomic_add(sub_pool->entry_size, &pool->active_entries_count);
216ff7b0d27SArkadi Sharshevsky return 0;
2176c5a688eSIdo Schimmel
2186c5a688eSIdo Schimmel err_alloc:
2196c5a688eSIdo Schimmel spin_unlock(&pool->counter_pool_lock);
2206c5a688eSIdo Schimmel return err;
221ff7b0d27SArkadi Sharshevsky }
222ff7b0d27SArkadi Sharshevsky
mlxsw_sp_counter_free(struct mlxsw_sp * mlxsw_sp,enum mlxsw_sp_counter_sub_pool_id sub_pool_id,unsigned int counter_index)223ff7b0d27SArkadi Sharshevsky void mlxsw_sp_counter_free(struct mlxsw_sp *mlxsw_sp,
224ff7b0d27SArkadi Sharshevsky enum mlxsw_sp_counter_sub_pool_id sub_pool_id,
225ff7b0d27SArkadi Sharshevsky unsigned int counter_index)
226ff7b0d27SArkadi Sharshevsky {
227ff7b0d27SArkadi Sharshevsky struct mlxsw_sp_counter_pool *pool = mlxsw_sp->counter_pool;
228ff7b0d27SArkadi Sharshevsky struct mlxsw_sp_counter_sub_pool *sub_pool;
229ff7b0d27SArkadi Sharshevsky int i;
230ff7b0d27SArkadi Sharshevsky
231ff7b0d27SArkadi Sharshevsky if (WARN_ON(counter_index >= pool->pool_size))
232ff7b0d27SArkadi Sharshevsky return;
233c33fbe94SJiri Pirko sub_pool = &pool->sub_pools[sub_pool_id];
2346c5a688eSIdo Schimmel spin_lock(&pool->counter_pool_lock);
235ff7b0d27SArkadi Sharshevsky for (i = 0; i < sub_pool->entry_size; i++)
236ff7b0d27SArkadi Sharshevsky __clear_bit(counter_index + i, pool->usage);
2376c5a688eSIdo Schimmel spin_unlock(&pool->counter_pool_lock);
2384e145fc6SJiri Pirko atomic_sub(sub_pool->entry_size, &sub_pool->active_entries_count);
2394e145fc6SJiri Pirko atomic_sub(sub_pool->entry_size, &pool->active_entries_count);
240ff7b0d27SArkadi Sharshevsky }
241d53cdbb8SJiri Pirko
mlxsw_sp_counter_resources_register(struct mlxsw_core * mlxsw_core)242d53cdbb8SJiri Pirko int mlxsw_sp_counter_resources_register(struct mlxsw_core *mlxsw_core)
243d53cdbb8SJiri Pirko {
244d53cdbb8SJiri Pirko static struct devlink_resource_size_params size_params;
245d53cdbb8SJiri Pirko struct devlink *devlink = priv_to_devlink(mlxsw_core);
246d53cdbb8SJiri Pirko const struct mlxsw_sp_counter_sub_pool *sub_pool;
247ab8c4cc6SJiri Pirko unsigned int total_bank_config;
248d53cdbb8SJiri Pirko u64 sub_pool_size;
249d53cdbb8SJiri Pirko u64 base_index;
250d53cdbb8SJiri Pirko u64 pool_size;
251d53cdbb8SJiri Pirko u64 bank_size;
252d53cdbb8SJiri Pirko int err;
253d53cdbb8SJiri Pirko int i;
254d53cdbb8SJiri Pirko
255d53cdbb8SJiri Pirko if (!MLXSW_CORE_RES_VALID(mlxsw_core, COUNTER_POOL_SIZE) ||
256d53cdbb8SJiri Pirko !MLXSW_CORE_RES_VALID(mlxsw_core, COUNTER_BANK_SIZE))
257d53cdbb8SJiri Pirko return -EIO;
258d53cdbb8SJiri Pirko
259d53cdbb8SJiri Pirko pool_size = MLXSW_CORE_RES_GET(mlxsw_core, COUNTER_POOL_SIZE);
260d53cdbb8SJiri Pirko bank_size = MLXSW_CORE_RES_GET(mlxsw_core, COUNTER_BANK_SIZE);
261d53cdbb8SJiri Pirko
262d53cdbb8SJiri Pirko devlink_resource_size_params_init(&size_params, pool_size,
263d53cdbb8SJiri Pirko pool_size, bank_size,
264d53cdbb8SJiri Pirko DEVLINK_RESOURCE_UNIT_ENTRY);
265*72a4c8c9SJiri Pirko err = devl_resource_register(devlink,
266d53cdbb8SJiri Pirko MLXSW_SP_RESOURCE_NAME_COUNTERS,
267d53cdbb8SJiri Pirko pool_size,
268d53cdbb8SJiri Pirko MLXSW_SP_RESOURCE_COUNTERS,
269d53cdbb8SJiri Pirko DEVLINK_RESOURCE_ID_PARENT_TOP,
270d53cdbb8SJiri Pirko &size_params);
271d53cdbb8SJiri Pirko if (err)
272d53cdbb8SJiri Pirko return err;
273d53cdbb8SJiri Pirko
274d53cdbb8SJiri Pirko /* Allocation is based on bank count which should be
275d53cdbb8SJiri Pirko * specified for each sub pool statically.
276d53cdbb8SJiri Pirko */
277ab8c4cc6SJiri Pirko total_bank_config = 0;
278d53cdbb8SJiri Pirko base_index = 0;
279d53cdbb8SJiri Pirko for (i = 0; i < ARRAY_SIZE(mlxsw_sp_counter_sub_pools); i++) {
280d53cdbb8SJiri Pirko sub_pool = &mlxsw_sp_counter_sub_pools[i];
281d53cdbb8SJiri Pirko sub_pool_size = sub_pool->bank_count * bank_size;
282d53cdbb8SJiri Pirko /* The last bank can't be fully used */
283d53cdbb8SJiri Pirko if (base_index + sub_pool_size > pool_size)
284d53cdbb8SJiri Pirko sub_pool_size = pool_size - base_index;
285d53cdbb8SJiri Pirko base_index += sub_pool_size;
286d53cdbb8SJiri Pirko
287d53cdbb8SJiri Pirko devlink_resource_size_params_init(&size_params, sub_pool_size,
288d53cdbb8SJiri Pirko sub_pool_size, bank_size,
289d53cdbb8SJiri Pirko DEVLINK_RESOURCE_UNIT_ENTRY);
290*72a4c8c9SJiri Pirko err = devl_resource_register(devlink,
291d53cdbb8SJiri Pirko sub_pool->resource_name,
292d53cdbb8SJiri Pirko sub_pool_size,
293d53cdbb8SJiri Pirko sub_pool->resource_id,
294d53cdbb8SJiri Pirko MLXSW_SP_RESOURCE_COUNTERS,
295d53cdbb8SJiri Pirko &size_params);
296d53cdbb8SJiri Pirko if (err)
297d53cdbb8SJiri Pirko return err;
298ab8c4cc6SJiri Pirko total_bank_config += sub_pool->bank_count;
299d53cdbb8SJiri Pirko }
300ab8c4cc6SJiri Pirko
301ab8c4cc6SJiri Pirko /* Check config is valid, no bank over subscription */
302c31f0ea7SNathan Chancellor if (WARN_ON(total_bank_config > div64_u64(pool_size, bank_size) + 1))
303ab8c4cc6SJiri Pirko return -EINVAL;
304ab8c4cc6SJiri Pirko
305d53cdbb8SJiri Pirko return 0;
306d53cdbb8SJiri Pirko }
307