1703faabfSKonstantin Ananyev/*
2703faabfSKonstantin Ananyev * Copyright (c) 2019  Intel Corporation.
3703faabfSKonstantin Ananyev * Licensed under the Apache License, Version 2.0 (the "License");
4703faabfSKonstantin Ananyev * you may not use this file except in compliance with the License.
5703faabfSKonstantin Ananyev * You may obtain a copy of the License at:
6703faabfSKonstantin Ananyev *
7703faabfSKonstantin Ananyev *     http://www.apache.org/licenses/LICENSE-2.0
8703faabfSKonstantin Ananyev *
9703faabfSKonstantin Ananyev * Unless required by applicable law or agreed to in writing, software
10703faabfSKonstantin Ananyev * distributed under the License is distributed on an "AS IS" BASIS,
11703faabfSKonstantin Ananyev * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12703faabfSKonstantin Ananyev * See the License for the specific language governing permissions and
13703faabfSKonstantin Ananyev * limitations under the License.
14703faabfSKonstantin Ananyev */
15703faabfSKonstantin Ananyev
16703faabfSKonstantin Ananyev#ifndef _TLE_MEMTANK_PUB_H_
17703faabfSKonstantin Ananyev#define _TLE_MEMTANK_PUB_H_
18703faabfSKonstantin Ananyev
19703faabfSKonstantin Ananyev#include <tle_memtank.h>
20703faabfSKonstantin Ananyev
21703faabfSKonstantin Ananyev#ifdef __cplusplus
22703faabfSKonstantin Ananyevextern "C" {
23703faabfSKonstantin Ananyev#endif
24703faabfSKonstantin Ananyev
25703faabfSKonstantin Ananyev/**
26703faabfSKonstantin Ananyev * @file
27703faabfSKonstantin Ananyev * TLE memtank public
28703faabfSKonstantin Ananyev * It is not recommended to include this file directly,
29703faabfSKonstantin Ananyev * include <tle_memtank.h> instead.
30703faabfSKonstantin Ananyev */
31703faabfSKonstantin Ananyev
32703faabfSKonstantin Ananyevstruct tle_memtank {
33703faabfSKonstantin Ananyev	rte_spinlock_t lock;
34703faabfSKonstantin Ananyev	uint32_t min_free;
35703faabfSKonstantin Ananyev	uint32_t max_free;
36703faabfSKonstantin Ananyev	uint32_t nb_free;
37703faabfSKonstantin Ananyev	void *free[];
38703faabfSKonstantin Ananyev} __rte_cache_aligned;
39703faabfSKonstantin Ananyev
40703faabfSKonstantin Ananyev
41703faabfSKonstantin Ananyevstatic inline void
42703faabfSKonstantin Ananyev_copy_objs(void *dst[], void * const src[], uint32_t num)
43703faabfSKonstantin Ananyev{
44703faabfSKonstantin Ananyev	uint32_t i, n;
45703faabfSKonstantin Ananyev
46703faabfSKonstantin Ananyev	n = RTE_ALIGN_FLOOR(num, 4);
47703faabfSKonstantin Ananyev
48703faabfSKonstantin Ananyev	for (i = 0; i != n; i += 4) {
49703faabfSKonstantin Ananyev		dst[i] = src[i];
50703faabfSKonstantin Ananyev		dst[i + 1] = src[i + 1];
51703faabfSKonstantin Ananyev		dst[i + 2] = src[i + 2];
52703faabfSKonstantin Ananyev		dst[i + 3] = src[i + 3];
53703faabfSKonstantin Ananyev	}
54703faabfSKonstantin Ananyev
55703faabfSKonstantin Ananyev	switch (num % 4) {
56703faabfSKonstantin Ananyev	case 3:
57703faabfSKonstantin Ananyev		dst[i + 2] = src[i + 2];
58703faabfSKonstantin Ananyev		/* fallthrough */
59703faabfSKonstantin Ananyev	case 2:
60703faabfSKonstantin Ananyev		dst[i + 1] = src[i + 1];
61703faabfSKonstantin Ananyev		/* fallthrough */
62703faabfSKonstantin Ananyev	case 1:
63703faabfSKonstantin Ananyev		dst[i] = src[i];
64703faabfSKonstantin Ananyev		/* fallthrough */
65703faabfSKonstantin Ananyev	}
66703faabfSKonstantin Ananyev}
67703faabfSKonstantin Ananyev
68703faabfSKonstantin Ananyevstatic inline uint32_t
69703faabfSKonstantin Ananyev_get_free(struct tle_memtank *t, void *obj[], uint32_t num)
70703faabfSKonstantin Ananyev{
71703faabfSKonstantin Ananyev	uint32_t len, n;
72703faabfSKonstantin Ananyev
73703faabfSKonstantin Ananyev	rte_spinlock_lock(&t->lock);
74703faabfSKonstantin Ananyev
75703faabfSKonstantin Ananyev	len = t->nb_free;
76703faabfSKonstantin Ananyev	n = RTE_MIN(num, len);
77703faabfSKonstantin Ananyev	len -= n;
78703faabfSKonstantin Ananyev	_copy_objs(obj, t->free + len, n);
79703faabfSKonstantin Ananyev	t->nb_free = len;
80703faabfSKonstantin Ananyev
81703faabfSKonstantin Ananyev	rte_spinlock_unlock(&t->lock);
82703faabfSKonstantin Ananyev	return n;
83703faabfSKonstantin Ananyev}
84703faabfSKonstantin Ananyev
85703faabfSKonstantin Ananyevstatic inline uint32_t
86703faabfSKonstantin Ananyev_put_free(struct tle_memtank *t, void * const obj[], uint32_t num)
87703faabfSKonstantin Ananyev{
88703faabfSKonstantin Ananyev	uint32_t len, n;
89703faabfSKonstantin Ananyev
90703faabfSKonstantin Ananyev	rte_spinlock_lock(&t->lock);
91703faabfSKonstantin Ananyev
92703faabfSKonstantin Ananyev	len = t->nb_free;
93703faabfSKonstantin Ananyev	n = t->max_free - len;
94703faabfSKonstantin Ananyev	n = RTE_MIN(num, n);
95703faabfSKonstantin Ananyev	_copy_objs(t->free + len, obj, n);
96703faabfSKonstantin Ananyev	t->nb_free = len + n;
97703faabfSKonstantin Ananyev
98703faabfSKonstantin Ananyev	rte_spinlock_unlock(&t->lock);
99703faabfSKonstantin Ananyev	return n;
100703faabfSKonstantin Ananyev}
101703faabfSKonstantin Ananyev
102703faabfSKonstantin Ananyevstatic inline void
103703faabfSKonstantin Ananyev_fill_free(struct tle_memtank *t, uint32_t num, uint32_t flags)
104703faabfSKonstantin Ananyev{
105703faabfSKonstantin Ananyev	uint32_t k, n;
106703faabfSKonstantin Ananyev	void *free[num];
107703faabfSKonstantin Ananyev
108703faabfSKonstantin Ananyev	k = tle_memtank_chunk_alloc(t, free, RTE_DIM(free), flags);
109703faabfSKonstantin Ananyev	n = _put_free(t, free, k);
110703faabfSKonstantin Ananyev	if (n != k)
111703faabfSKonstantin Ananyev		tle_memtank_chunk_free(t, free + n, k - n, 0);
112703faabfSKonstantin Ananyev}
113703faabfSKonstantin Ananyev
114703faabfSKonstantin Ananyevstatic inline uint32_t
115703faabfSKonstantin Ananyevtle_memtank_alloc(struct tle_memtank *t, void *obj[], uint32_t num,
116703faabfSKonstantin Ananyev	uint32_t flags)
117703faabfSKonstantin Ananyev{
118703faabfSKonstantin Ananyev	uint32_t n;
119703faabfSKonstantin Ananyev
120703faabfSKonstantin Ananyev	n = _get_free(t, obj, num);
121703faabfSKonstantin Ananyev
122703faabfSKonstantin Ananyev	/* not enough free objects, try to allocate via memchunks */
123703faabfSKonstantin Ananyev	if (n != num && flags != 0) {
124703faabfSKonstantin Ananyev		n += tle_memtank_chunk_alloc(t, obj + n, num - n, flags);
125703faabfSKonstantin Ananyev
126703faabfSKonstantin Ananyev		/* refill *free* tank */
127703faabfSKonstantin Ananyev		if (n == num)
128703faabfSKonstantin Ananyev			_fill_free(t, t->min_free, flags);
129703faabfSKonstantin Ananyev	}
130703faabfSKonstantin Ananyev
131703faabfSKonstantin Ananyev	return n;
132703faabfSKonstantin Ananyev}
133703faabfSKonstantin Ananyev
134703faabfSKonstantin Ananyevstatic inline void
135703faabfSKonstantin Ananyevtle_memtank_free(struct tle_memtank *t, void * const obj[], uint32_t num,
136703faabfSKonstantin Ananyev	uint32_t flags)
137703faabfSKonstantin Ananyev{
138703faabfSKonstantin Ananyev	uint32_t n;
139703faabfSKonstantin Ananyev
140703faabfSKonstantin Ananyev	n = _put_free(t, obj, num);
141703faabfSKonstantin Ananyev	if (n != num)
142703faabfSKonstantin Ananyev		tle_memtank_chunk_free(t, obj + n, num - n, flags);
143703faabfSKonstantin Ananyev}
144703faabfSKonstantin Ananyev
145703faabfSKonstantin Ananyev#ifdef __cplusplus
146703faabfSKonstantin Ananyev}
147703faabfSKonstantin Ananyev#endif
148703faabfSKonstantin Ananyev
149703faabfSKonstantin Ananyev#endif /* _TLE_MEMTANK_PUB_H_ */