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