1// SPDX-License-Identifier: GPL-2.0
2/*
3 * Copyright (C) 2018-2022 Marvell International Ltd.
4 *
5 * PKI Support.
6 */
7
8#include <time.h>
9#include <log.h>
10#include <linux/delay.h>
11
12#include <mach/cvmx-regs.h>
13#include <mach/cvmx-csr.h>
14#include <mach/cvmx-bootmem.h>
15#include <mach/octeon-model.h>
16#include <mach/cvmx-fuse.h>
17#include <mach/octeon-feature.h>
18#include <mach/cvmx-qlm.h>
19#include <mach/octeon_qlm.h>
20#include <mach/cvmx-pcie.h>
21#include <mach/cvmx-coremask.h>
22
23#include <mach/cvmx-global-resources.h>
24
25#include <mach/cvmx-pki-defs.h>
26#include <mach/cvmx-pko-defs.h>
27
28#include <mach/cvmx-pki.h>
29#include <mach/cvmx-helper.h>
30#include <mach/cvmx-helper-board.h>
31#include <mach/cvmx-helper-cfg.h>
32
33static s32 cvmx_pki_style_refcnt[CVMX_MAX_NODES][CVMX_PKI_NUM_INTERNAL_STYLE];
34
35/**
36 * This function allocates/reserves a style from pool of global styles per node.
37 * @param node	node to allocate style from.
38 * @param style	style to allocate, if -1 it will be allocated
39 *		first available style from style resource. If index is positive
40 *		number and in range, it will try to allocate specified style.
41 * @return	style number on success,
42 *		-1 on alloc failure.
43 *		-2 on resource already reserved.
44 */
45int cvmx_pki_style_alloc(int node, int style)
46{
47	int rs;
48
49	if (cvmx_create_global_resource_range(CVMX_GR_TAG_STYLE(node),
50					      CVMX_PKI_NUM_INTERNAL_STYLE)) {
51		printf("ERROR: Failed to create styles global resource\n");
52		return -1;
53	}
54	if (style >= 0) {
55		/* Reserving specific style, use refcnt for sharing */
56		rs = cvmx_atomic_fetch_and_add32(
57			&cvmx_pki_style_refcnt[node][style], 1);
58		if (rs > 0)
59			return CVMX_RESOURCE_ALREADY_RESERVED;
60
61		rs = cvmx_reserve_global_resource_range(CVMX_GR_TAG_STYLE(node),
62							style, style, 1);
63		if (rs == -1) {
64			/* This means the style is taken by another app */
65			printf("ERROR: style %d is reserved by another app\n",
66			       style);
67			cvmx_atomic_fetch_and_add32(
68				&cvmx_pki_style_refcnt[node][style], -1);
69			return CVMX_RESOURCE_ALLOC_FAILED;
70		}
71	} else {
72		/* Allocate first available style */
73		rs = cvmx_allocate_global_resource_range(
74			CVMX_GR_TAG_STYLE(node), style, 1, 1);
75		if (rs < 0) {
76			printf("ERROR: Failed to allocate style, none available\n");
77			return CVMX_RESOURCE_ALLOC_FAILED;
78		}
79		style = rs;
80		/* Increment refcnt for newly created style */
81		cvmx_atomic_fetch_and_add32(&cvmx_pki_style_refcnt[node][style],
82					    1);
83	}
84	return style;
85}
86
87/**
88 * This function frees a style from pool of global styles per node.
89 * @param node	 node to free style from.
90 * @param style	 style to free
91 * @return	 0 on success, -1 on failure or
92 * if the style is shared a positive count of remaining users for this style.
93 */
94int cvmx_pki_style_free(int node, int style)
95{
96	int rs;
97
98	rs = cvmx_atomic_fetch_and_add32(&cvmx_pki_style_refcnt[node][style],
99					 -1);
100	if (rs > 1)
101		return rs - 1;
102
103	if (cvmx_free_global_resource_range_with_base(CVMX_GR_TAG_STYLE(node),
104						      style, 1) == -1) {
105		printf("ERROR Failed to release style %d\n", (int)style);
106		return -1;
107	}
108	return 0;
109}
110
111/**
112 * This function allocates/reserves a cluster group from per node
113   cluster group resources.
114 * @param node		node to allocate cluster group from.
115   @param cl_grp	cluster group to allocate/reserve, if -1 ,
116 *			allocate any available cluster group.
117 * @return		cluster group number
118 *			-1 on alloc failure.
119 *			-2 on resource already reserved.
120 */
121int cvmx_pki_cluster_grp_alloc(int node, int cl_grp)
122{
123	int rs;
124
125	if (node >= CVMX_MAX_NODES) {
126		printf("ERROR: Invalid node number %d\n", node);
127		return -1;
128	}
129	if (cvmx_create_global_resource_range(CVMX_GR_TAG_CLUSTER_GRP(node),
130					      CVMX_PKI_NUM_CLUSTER_GROUP)) {
131		printf("ERROR: Failed to create Cluster group global resource\n");
132		return -1;
133	}
134	if (cl_grp >= 0) {
135		rs = cvmx_reserve_global_resource_range(
136			CVMX_GR_TAG_CLUSTER_GRP(node), 0, cl_grp, 1);
137		if (rs == -1) {
138			debug("INFO: cl_grp %d is already reserved\n",
139			      (int)cl_grp);
140			return CVMX_RESOURCE_ALREADY_RESERVED;
141		}
142	} else {
143		rs = cvmx_allocate_global_resource_range(
144			CVMX_GR_TAG_CLUSTER_GRP(node), 0, 1, 1);
145		if (rs == -1) {
146			debug("Warning: Failed to alloc cluster grp\n");
147			return CVMX_RESOURCE_ALLOC_FAILED;
148		}
149	}
150	cl_grp = rs;
151	return cl_grp;
152}
153
154/**
155 * This function allocates/reserves a pcam entry from node
156 * @param node		node to allocate pcam entry from.
157 * @param index	index of pacm entry (0-191), if -1 ,
158 *			allocate any available pcam entry.
159 * @param bank		pcam bank where to allocate/reserve pcan entry from
160 * @param cluster_mask  mask of clusters from which pcam entry is needed.
161 * @return		pcam entry of -1 on failure
162 */
163int cvmx_pki_pcam_entry_alloc(int node, int index, int bank, u64 cluster_mask)
164{
165	int rs = 0;
166	unsigned int cluster;
167
168	for (cluster = 0; cluster < CVMX_PKI_NUM_CLUSTER; cluster++) {
169		if ((cluster_mask & (1 << cluster)) == 0)
170			continue;
171		rs = cvmx_create_global_resource_range(
172			CVMX_GR_TAG_PCAM(node, cluster, bank),
173			CVMX_PKI_TOTAL_PCAM_ENTRY);
174		if (rs != 0) {
175			printf("ERROR: Failed to create pki pcam global resource\n");
176			return -1;
177		}
178		if (index >= 0)
179			rs = cvmx_reserve_global_resource_range(
180				CVMX_GR_TAG_PCAM(node, cluster, bank), cluster,
181				index, 1);
182		else
183			rs = cvmx_allocate_global_resource_range(
184				CVMX_GR_TAG_PCAM(node, cluster, bank), cluster,
185				1, 1);
186		if (rs == -1) {
187			printf("ERROR: PCAM :index %d not available in cluster %d bank %d",
188			       (int)index, (int)cluster, bank);
189			return -1;
190		}
191	} /* for cluster */
192	index = rs;
193	/* implement cluster handle for pass2, for now assume
194	all clusters will have same base index*/
195	return index;
196}
197
198/**
199 * This function allocates/reserves QPG table entries per node.
200 * @param node		node number.
201 * @param base_offset	base_offset in qpg table. If -1, first available
202 *			qpg base_offset will be allocated. If base_offset is positive
203 *			number and in range, it will try to allocate specified base_offset.
204 * @param count		number of consecutive qpg entries to allocate. They will be consecutive
205 *                       from base offset.
206 * @return		qpg table base offset number on success
207 *			-1 on alloc failure.
208 *			-2 on resource already reserved.
209 */
210int cvmx_pki_qpg_entry_alloc(int node, int base_offset, int count)
211{
212	int rs;
213
214	if (cvmx_create_global_resource_range(CVMX_GR_TAG_QPG_ENTRY(node),
215					      CVMX_PKI_NUM_QPG_ENTRY)) {
216		printf("ERROR: Failed to create qpg_entry global resource\n");
217		return -1;
218	}
219	if (base_offset >= 0) {
220		rs = cvmx_reserve_global_resource_range(
221			CVMX_GR_TAG_QPG_ENTRY(node), base_offset, base_offset,
222			count);
223		if (rs == -1) {
224			debug("INFO: qpg entry %d is already reserved\n",
225			      (int)base_offset);
226			return CVMX_RESOURCE_ALREADY_RESERVED;
227		}
228	} else {
229		rs = cvmx_allocate_global_resource_range(
230			CVMX_GR_TAG_QPG_ENTRY(node), base_offset, count, 1);
231		if (rs == -1) {
232			printf("ERROR: Failed to allocate qpg entry\n");
233			return CVMX_RESOURCE_ALLOC_FAILED;
234		}
235	}
236	base_offset = rs;
237	return base_offset;
238}
239
240/**
241 * This function frees QPG table entries per node.
242 * @param node		node number.
243 * @param base_offset	base_offset in qpg table. If -1, first available
244 *			qpg base_offset will be allocated. If base_offset is positive
245 *			number and in range, it will try to allocate specified base_offset.
246 * @param count		number of consecutive qpg entries to allocate. They will be consecutive
247 *			from base offset.
248 * @return		qpg table base offset number on success, -1 on failure.
249 */
250int cvmx_pki_qpg_entry_free(int node, int base_offset, int count)
251{
252	if (cvmx_free_global_resource_range_with_base(
253		    CVMX_GR_TAG_QPG_ENTRY(node), base_offset, count) == -1) {
254		printf("ERROR Failed to release qpg offset %d",
255		       (int)base_offset);
256		return -1;
257	}
258	return 0;
259}
260
261int cvmx_pki_mtag_idx_alloc(int node, int idx)
262{
263	if (cvmx_create_global_resource_range(CVMX_GR_TAG_MTAG_IDX(node),
264					      CVMX_PKI_NUM_MTAG_IDX)) {
265		printf("ERROR: Failed to create MTAG-IDX global resource\n");
266		return -1;
267	}
268	if (idx >= 0) {
269		idx = cvmx_reserve_global_resource_range(
270			CVMX_GR_TAG_MTAG_IDX(node), idx, idx, 1);
271		if (idx == -1) {
272			debug("INFO: MTAG index %d is already reserved\n",
273			      (int)idx);
274			return CVMX_RESOURCE_ALREADY_RESERVED;
275		}
276	} else {
277		idx = cvmx_allocate_global_resource_range(
278			CVMX_GR_TAG_MTAG_IDX(node), idx, 1, 1);
279		if (idx == -1) {
280			printf("ERROR: Failed to allocate MTAG index\n");
281			return CVMX_RESOURCE_ALLOC_FAILED;
282		}
283	}
284	return idx;
285}
286