196de2506SJakub Kicinski // SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
296de2506SJakub Kicinski /* Copyright (C) 2018 Netronome Systems, Inc. */
3a0d163f4SJakub Kicinski 
4a0d163f4SJakub Kicinski #include <linux/kernel.h>
5a0d163f4SJakub Kicinski #include <net/devlink.h>
6a0d163f4SJakub Kicinski 
7a0d163f4SJakub Kicinski #include "nfpcore/nfp_cpp.h"
8a0d163f4SJakub Kicinski #include "nfpcore/nfp_nffw.h"
9a0d163f4SJakub Kicinski #include "nfp_abi.h"
10a0d163f4SJakub Kicinski #include "nfp_app.h"
11a0d163f4SJakub Kicinski #include "nfp_main.h"
12a0d163f4SJakub Kicinski 
nfp_shared_buf_pool_unit(struct nfp_pf * pf,unsigned int sb)13a0d163f4SJakub Kicinski static u32 nfp_shared_buf_pool_unit(struct nfp_pf *pf, unsigned int sb)
14a0d163f4SJakub Kicinski {
15a0d163f4SJakub Kicinski 	__le32 sb_id = cpu_to_le32(sb);
16a0d163f4SJakub Kicinski 	unsigned int i;
17a0d163f4SJakub Kicinski 
18a0d163f4SJakub Kicinski 	for (i = 0; i < pf->num_shared_bufs; i++)
19a0d163f4SJakub Kicinski 		if (pf->shared_bufs[i].id == sb_id)
20a0d163f4SJakub Kicinski 			return le32_to_cpu(pf->shared_bufs[i].pool_size_unit);
21a0d163f4SJakub Kicinski 
22a0d163f4SJakub Kicinski 	WARN_ON_ONCE(1);
23a0d163f4SJakub Kicinski 	return 0;
24a0d163f4SJakub Kicinski }
25a0d163f4SJakub Kicinski 
nfp_shared_buf_pool_get(struct nfp_pf * pf,unsigned int sb,u16 pool_index,struct devlink_sb_pool_info * pool_info)26a0d163f4SJakub Kicinski int nfp_shared_buf_pool_get(struct nfp_pf *pf, unsigned int sb, u16 pool_index,
27a0d163f4SJakub Kicinski 			    struct devlink_sb_pool_info *pool_info)
28a0d163f4SJakub Kicinski {
29a0d163f4SJakub Kicinski 	struct nfp_shared_buf_pool_info_get get_data;
30a0d163f4SJakub Kicinski 	struct nfp_shared_buf_pool_id id = {
31a0d163f4SJakub Kicinski 		.shared_buf	= cpu_to_le32(sb),
32a0d163f4SJakub Kicinski 		.pool		= cpu_to_le32(pool_index),
33a0d163f4SJakub Kicinski 	};
34a0d163f4SJakub Kicinski 	unsigned int unit_size;
35a0d163f4SJakub Kicinski 	int n;
36a0d163f4SJakub Kicinski 
37a0d163f4SJakub Kicinski 	unit_size = nfp_shared_buf_pool_unit(pf, sb);
38a0d163f4SJakub Kicinski 	if (!unit_size)
39a0d163f4SJakub Kicinski 		return -EINVAL;
40a0d163f4SJakub Kicinski 
41a0d163f4SJakub Kicinski 	n = nfp_mbox_cmd(pf, NFP_MBOX_POOL_GET, &id, sizeof(id),
42a0d163f4SJakub Kicinski 			 &get_data, sizeof(get_data));
43a0d163f4SJakub Kicinski 	if (n < 0)
44a0d163f4SJakub Kicinski 		return n;
45a0d163f4SJakub Kicinski 	if (n < sizeof(get_data))
46a0d163f4SJakub Kicinski 		return -EIO;
47a0d163f4SJakub Kicinski 
48a0d163f4SJakub Kicinski 	pool_info->pool_type = le32_to_cpu(get_data.pool_type);
49a0d163f4SJakub Kicinski 	pool_info->threshold_type = le32_to_cpu(get_data.threshold_type);
50a0d163f4SJakub Kicinski 	pool_info->size = le32_to_cpu(get_data.size) * unit_size;
51bff5731dSJakub Kicinski 	pool_info->cell_size = unit_size;
52a0d163f4SJakub Kicinski 
53a0d163f4SJakub Kicinski 	return 0;
54a0d163f4SJakub Kicinski }
55a0d163f4SJakub Kicinski 
nfp_shared_buf_pool_set(struct nfp_pf * pf,unsigned int sb,u16 pool_index,u32 size,enum devlink_sb_threshold_type threshold_type)56a0d163f4SJakub Kicinski int nfp_shared_buf_pool_set(struct nfp_pf *pf, unsigned int sb,
57a0d163f4SJakub Kicinski 			    u16 pool_index, u32 size,
58a0d163f4SJakub Kicinski 			    enum devlink_sb_threshold_type threshold_type)
59a0d163f4SJakub Kicinski {
60a0d163f4SJakub Kicinski 	struct nfp_shared_buf_pool_info_set set_data = {
61a0d163f4SJakub Kicinski 		.id = {
62a0d163f4SJakub Kicinski 			.shared_buf	= cpu_to_le32(sb),
63a0d163f4SJakub Kicinski 			.pool		= cpu_to_le32(pool_index),
64a0d163f4SJakub Kicinski 		},
65a0d163f4SJakub Kicinski 		.threshold_type	= cpu_to_le32(threshold_type),
66a0d163f4SJakub Kicinski 	};
67a0d163f4SJakub Kicinski 	unsigned int unit_size;
68a0d163f4SJakub Kicinski 
69a0d163f4SJakub Kicinski 	unit_size = nfp_shared_buf_pool_unit(pf, sb);
70a0d163f4SJakub Kicinski 	if (!unit_size || size % unit_size)
71a0d163f4SJakub Kicinski 		return -EINVAL;
72a0d163f4SJakub Kicinski 	set_data.size = cpu_to_le32(size / unit_size);
73a0d163f4SJakub Kicinski 
74a0d163f4SJakub Kicinski 	return nfp_mbox_cmd(pf, NFP_MBOX_POOL_SET, &set_data, sizeof(set_data),
75a0d163f4SJakub Kicinski 			    NULL, 0);
76a0d163f4SJakub Kicinski }
77a0d163f4SJakub Kicinski 
nfp_shared_buf_register(struct nfp_pf * pf)78a0d163f4SJakub Kicinski int nfp_shared_buf_register(struct nfp_pf *pf)
79a0d163f4SJakub Kicinski {
80a0d163f4SJakub Kicinski 	struct devlink *devlink = priv_to_devlink(pf);
81a0d163f4SJakub Kicinski 	unsigned int i, num_entries, entry_sz;
82a0d163f4SJakub Kicinski 	struct nfp_cpp_area *sb_desc_area;
83a0d163f4SJakub Kicinski 	u8 __iomem *sb_desc;
84a0d163f4SJakub Kicinski 	int n, err;
85a0d163f4SJakub Kicinski 
86a0d163f4SJakub Kicinski 	if (!pf->mbox)
87a0d163f4SJakub Kicinski 		return 0;
88a0d163f4SJakub Kicinski 
89a0d163f4SJakub Kicinski 	n = nfp_pf_rtsym_read_optional(pf, NFP_SHARED_BUF_COUNT_SYM_NAME, 0);
90a0d163f4SJakub Kicinski 	if (n <= 0)
91a0d163f4SJakub Kicinski 		return n;
92a0d163f4SJakub Kicinski 	num_entries = n;
93a0d163f4SJakub Kicinski 
94a0d163f4SJakub Kicinski 	sb_desc = nfp_pf_map_rtsym(pf, "sb_tbl", NFP_SHARED_BUF_TABLE_SYM_NAME,
95a0d163f4SJakub Kicinski 				   num_entries * sizeof(pf->shared_bufs[0]),
96a0d163f4SJakub Kicinski 				   &sb_desc_area);
97a0d163f4SJakub Kicinski 	if (IS_ERR(sb_desc))
98a0d163f4SJakub Kicinski 		return PTR_ERR(sb_desc);
99a0d163f4SJakub Kicinski 
100a0d163f4SJakub Kicinski 	entry_sz = nfp_cpp_area_size(sb_desc_area) / num_entries;
101a0d163f4SJakub Kicinski 
102a0d163f4SJakub Kicinski 	pf->shared_bufs = kmalloc_array(num_entries, sizeof(pf->shared_bufs[0]),
103a0d163f4SJakub Kicinski 					GFP_KERNEL);
104a0d163f4SJakub Kicinski 	if (!pf->shared_bufs) {
105a0d163f4SJakub Kicinski 		err = -ENOMEM;
106a0d163f4SJakub Kicinski 		goto err_release_area;
107a0d163f4SJakub Kicinski 	}
108a0d163f4SJakub Kicinski 
109a0d163f4SJakub Kicinski 	for (i = 0; i < num_entries; i++) {
110a0d163f4SJakub Kicinski 		struct nfp_shared_buf *sb = &pf->shared_bufs[i];
111a0d163f4SJakub Kicinski 
112a0d163f4SJakub Kicinski 		/* Entries may be larger in future FW */
113a0d163f4SJakub Kicinski 		memcpy_fromio(sb, sb_desc + i * entry_sz, sizeof(*sb));
114a0d163f4SJakub Kicinski 
115a0d163f4SJakub Kicinski 		err = devlink_sb_register(devlink,
116a0d163f4SJakub Kicinski 					  le32_to_cpu(sb->id),
117a0d163f4SJakub Kicinski 					  le32_to_cpu(sb->size),
118a0d163f4SJakub Kicinski 					  le16_to_cpu(sb->ingress_pools_count),
119a0d163f4SJakub Kicinski 					  le16_to_cpu(sb->egress_pools_count),
120a0d163f4SJakub Kicinski 					  le16_to_cpu(sb->ingress_tc_count),
121a0d163f4SJakub Kicinski 					  le16_to_cpu(sb->egress_tc_count));
122a0d163f4SJakub Kicinski 		if (err)
123a0d163f4SJakub Kicinski 			goto err_unreg_prev;
124a0d163f4SJakub Kicinski 	}
125a0d163f4SJakub Kicinski 	pf->num_shared_bufs = num_entries;
126a0d163f4SJakub Kicinski 
127a0d163f4SJakub Kicinski 	nfp_cpp_area_release_free(sb_desc_area);
128a0d163f4SJakub Kicinski 
129a0d163f4SJakub Kicinski 	return 0;
130a0d163f4SJakub Kicinski 
131a0d163f4SJakub Kicinski err_unreg_prev:
132a0d163f4SJakub Kicinski 	while (i--)
133a0d163f4SJakub Kicinski 		devlink_sb_unregister(devlink,
134a0d163f4SJakub Kicinski 				      le32_to_cpu(pf->shared_bufs[i].id));
135a0d163f4SJakub Kicinski 	kfree(pf->shared_bufs);
136a0d163f4SJakub Kicinski err_release_area:
137a0d163f4SJakub Kicinski 	nfp_cpp_area_release_free(sb_desc_area);
138a0d163f4SJakub Kicinski 	return err;
139a0d163f4SJakub Kicinski }
140a0d163f4SJakub Kicinski 
nfp_shared_buf_unregister(struct nfp_pf * pf)141a0d163f4SJakub Kicinski void nfp_shared_buf_unregister(struct nfp_pf *pf)
142a0d163f4SJakub Kicinski {
143a0d163f4SJakub Kicinski 	struct devlink *devlink = priv_to_devlink(pf);
144a0d163f4SJakub Kicinski 	unsigned int i;
145a0d163f4SJakub Kicinski 
146a0d163f4SJakub Kicinski 	for (i = 0; i < pf->num_shared_bufs; i++)
147a0d163f4SJakub Kicinski 		devlink_sb_unregister(devlink,
148a0d163f4SJakub Kicinski 				      le32_to_cpu(pf->shared_bufs[i].id));
149a0d163f4SJakub Kicinski 	kfree(pf->shared_bufs);
150a0d163f4SJakub Kicinski }
151