xref: /OK3568_Linux_fs/kernel/drivers/net/dsa/sja1105/sja1105_devlink.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0
2*4882a593Smuzhiyun /* Copyright (c) 2018-2019, Vladimir Oltean <olteanv@gmail.com>
3*4882a593Smuzhiyun  * Copyright 2020 NXP Semiconductors
4*4882a593Smuzhiyun  */
5*4882a593Smuzhiyun #include "sja1105.h"
6*4882a593Smuzhiyun 
7*4882a593Smuzhiyun /* Since devlink regions have a fixed size and the static config has a variable
8*4882a593Smuzhiyun  * size, we need to calculate the maximum possible static config size by
9*4882a593Smuzhiyun  * creating a dummy config with all table entries populated to the max, and get
10*4882a593Smuzhiyun  * its packed length. This is done dynamically as opposed to simply hardcoding
11*4882a593Smuzhiyun  * a number, since currently not all static config tables are implemented, so
12*4882a593Smuzhiyun  * we are avoiding a possible code desynchronization.
13*4882a593Smuzhiyun  */
sja1105_static_config_get_max_size(struct sja1105_private * priv)14*4882a593Smuzhiyun static size_t sja1105_static_config_get_max_size(struct sja1105_private *priv)
15*4882a593Smuzhiyun {
16*4882a593Smuzhiyun 	struct sja1105_static_config config;
17*4882a593Smuzhiyun 	enum sja1105_blk_idx blk_idx;
18*4882a593Smuzhiyun 	int rc;
19*4882a593Smuzhiyun 
20*4882a593Smuzhiyun 	rc = sja1105_static_config_init(&config,
21*4882a593Smuzhiyun 					priv->info->static_ops,
22*4882a593Smuzhiyun 					priv->info->device_id);
23*4882a593Smuzhiyun 	if (rc)
24*4882a593Smuzhiyun 		return 0;
25*4882a593Smuzhiyun 
26*4882a593Smuzhiyun 	for (blk_idx = 0; blk_idx < BLK_IDX_MAX; blk_idx++) {
27*4882a593Smuzhiyun 		struct sja1105_table *table = &config.tables[blk_idx];
28*4882a593Smuzhiyun 
29*4882a593Smuzhiyun 		table->entry_count = table->ops->max_entry_count;
30*4882a593Smuzhiyun 	}
31*4882a593Smuzhiyun 
32*4882a593Smuzhiyun 	return sja1105_static_config_get_length(&config);
33*4882a593Smuzhiyun }
34*4882a593Smuzhiyun 
35*4882a593Smuzhiyun static int
sja1105_region_static_config_snapshot(struct devlink * dl,const struct devlink_region_ops * ops,struct netlink_ext_ack * extack,u8 ** data)36*4882a593Smuzhiyun sja1105_region_static_config_snapshot(struct devlink *dl,
37*4882a593Smuzhiyun 				      const struct devlink_region_ops *ops,
38*4882a593Smuzhiyun 				      struct netlink_ext_ack *extack,
39*4882a593Smuzhiyun 				      u8 **data)
40*4882a593Smuzhiyun {
41*4882a593Smuzhiyun 	struct dsa_switch *ds = dsa_devlink_to_ds(dl);
42*4882a593Smuzhiyun 	struct sja1105_private *priv = ds->priv;
43*4882a593Smuzhiyun 	size_t max_len, len;
44*4882a593Smuzhiyun 
45*4882a593Smuzhiyun 	len = sja1105_static_config_get_length(&priv->static_config);
46*4882a593Smuzhiyun 	max_len = sja1105_static_config_get_max_size(priv);
47*4882a593Smuzhiyun 
48*4882a593Smuzhiyun 	*data = kcalloc(max_len, sizeof(u8), GFP_KERNEL);
49*4882a593Smuzhiyun 	if (!*data)
50*4882a593Smuzhiyun 		return -ENOMEM;
51*4882a593Smuzhiyun 
52*4882a593Smuzhiyun 	return static_config_buf_prepare_for_upload(priv, *data, len);
53*4882a593Smuzhiyun }
54*4882a593Smuzhiyun 
55*4882a593Smuzhiyun static struct devlink_region_ops sja1105_region_static_config_ops = {
56*4882a593Smuzhiyun 	.name = "static-config",
57*4882a593Smuzhiyun 	.snapshot = sja1105_region_static_config_snapshot,
58*4882a593Smuzhiyun 	.destructor = kfree,
59*4882a593Smuzhiyun };
60*4882a593Smuzhiyun 
61*4882a593Smuzhiyun enum sja1105_region_id {
62*4882a593Smuzhiyun 	SJA1105_REGION_STATIC_CONFIG = 0,
63*4882a593Smuzhiyun };
64*4882a593Smuzhiyun 
65*4882a593Smuzhiyun struct sja1105_region {
66*4882a593Smuzhiyun 	const struct devlink_region_ops *ops;
67*4882a593Smuzhiyun 	size_t (*get_size)(struct sja1105_private *priv);
68*4882a593Smuzhiyun };
69*4882a593Smuzhiyun 
70*4882a593Smuzhiyun static struct sja1105_region sja1105_regions[] = {
71*4882a593Smuzhiyun 	[SJA1105_REGION_STATIC_CONFIG] = {
72*4882a593Smuzhiyun 		.ops = &sja1105_region_static_config_ops,
73*4882a593Smuzhiyun 		.get_size = sja1105_static_config_get_max_size,
74*4882a593Smuzhiyun 	},
75*4882a593Smuzhiyun };
76*4882a593Smuzhiyun 
sja1105_setup_devlink_regions(struct dsa_switch * ds)77*4882a593Smuzhiyun static int sja1105_setup_devlink_regions(struct dsa_switch *ds)
78*4882a593Smuzhiyun {
79*4882a593Smuzhiyun 	int i, num_regions = ARRAY_SIZE(sja1105_regions);
80*4882a593Smuzhiyun 	struct sja1105_private *priv = ds->priv;
81*4882a593Smuzhiyun 	const struct devlink_region_ops *ops;
82*4882a593Smuzhiyun 	struct devlink_region *region;
83*4882a593Smuzhiyun 	u64 size;
84*4882a593Smuzhiyun 
85*4882a593Smuzhiyun 	priv->regions = kcalloc(num_regions, sizeof(struct devlink_region *),
86*4882a593Smuzhiyun 				GFP_KERNEL);
87*4882a593Smuzhiyun 	if (!priv->regions)
88*4882a593Smuzhiyun 		return -ENOMEM;
89*4882a593Smuzhiyun 
90*4882a593Smuzhiyun 	for (i = 0; i < num_regions; i++) {
91*4882a593Smuzhiyun 		size = sja1105_regions[i].get_size(priv);
92*4882a593Smuzhiyun 		ops = sja1105_regions[i].ops;
93*4882a593Smuzhiyun 
94*4882a593Smuzhiyun 		region = dsa_devlink_region_create(ds, ops, 1, size);
95*4882a593Smuzhiyun 		if (IS_ERR(region)) {
96*4882a593Smuzhiyun 			while (--i >= 0)
97*4882a593Smuzhiyun 				dsa_devlink_region_destroy(priv->regions[i]);
98*4882a593Smuzhiyun 
99*4882a593Smuzhiyun 			kfree(priv->regions);
100*4882a593Smuzhiyun 			return PTR_ERR(region);
101*4882a593Smuzhiyun 		}
102*4882a593Smuzhiyun 
103*4882a593Smuzhiyun 		priv->regions[i] = region;
104*4882a593Smuzhiyun 	}
105*4882a593Smuzhiyun 
106*4882a593Smuzhiyun 	return 0;
107*4882a593Smuzhiyun }
108*4882a593Smuzhiyun 
sja1105_teardown_devlink_regions(struct dsa_switch * ds)109*4882a593Smuzhiyun static void sja1105_teardown_devlink_regions(struct dsa_switch *ds)
110*4882a593Smuzhiyun {
111*4882a593Smuzhiyun 	int i, num_regions = ARRAY_SIZE(sja1105_regions);
112*4882a593Smuzhiyun 	struct sja1105_private *priv = ds->priv;
113*4882a593Smuzhiyun 
114*4882a593Smuzhiyun 	for (i = 0; i < num_regions; i++)
115*4882a593Smuzhiyun 		dsa_devlink_region_destroy(priv->regions[i]);
116*4882a593Smuzhiyun 
117*4882a593Smuzhiyun 	kfree(priv->regions);
118*4882a593Smuzhiyun }
119*4882a593Smuzhiyun 
sja1105_best_effort_vlan_filtering_get(struct sja1105_private * priv,bool * be_vlan)120*4882a593Smuzhiyun static int sja1105_best_effort_vlan_filtering_get(struct sja1105_private *priv,
121*4882a593Smuzhiyun 						  bool *be_vlan)
122*4882a593Smuzhiyun {
123*4882a593Smuzhiyun 	*be_vlan = priv->best_effort_vlan_filtering;
124*4882a593Smuzhiyun 
125*4882a593Smuzhiyun 	return 0;
126*4882a593Smuzhiyun }
127*4882a593Smuzhiyun 
sja1105_best_effort_vlan_filtering_set(struct sja1105_private * priv,bool be_vlan)128*4882a593Smuzhiyun static int sja1105_best_effort_vlan_filtering_set(struct sja1105_private *priv,
129*4882a593Smuzhiyun 						  bool be_vlan)
130*4882a593Smuzhiyun {
131*4882a593Smuzhiyun 	struct dsa_switch *ds = priv->ds;
132*4882a593Smuzhiyun 	bool vlan_filtering;
133*4882a593Smuzhiyun 	int port;
134*4882a593Smuzhiyun 	int rc;
135*4882a593Smuzhiyun 
136*4882a593Smuzhiyun 	priv->best_effort_vlan_filtering = be_vlan;
137*4882a593Smuzhiyun 
138*4882a593Smuzhiyun 	rtnl_lock();
139*4882a593Smuzhiyun 	for (port = 0; port < ds->num_ports; port++) {
140*4882a593Smuzhiyun 		struct switchdev_trans trans;
141*4882a593Smuzhiyun 		struct dsa_port *dp;
142*4882a593Smuzhiyun 
143*4882a593Smuzhiyun 		if (!dsa_is_user_port(ds, port))
144*4882a593Smuzhiyun 			continue;
145*4882a593Smuzhiyun 
146*4882a593Smuzhiyun 		dp = dsa_to_port(ds, port);
147*4882a593Smuzhiyun 		vlan_filtering = dsa_port_is_vlan_filtering(dp);
148*4882a593Smuzhiyun 
149*4882a593Smuzhiyun 		trans.ph_prepare = true;
150*4882a593Smuzhiyun 		rc = sja1105_vlan_filtering(ds, port, vlan_filtering, &trans);
151*4882a593Smuzhiyun 		if (rc)
152*4882a593Smuzhiyun 			break;
153*4882a593Smuzhiyun 
154*4882a593Smuzhiyun 		trans.ph_prepare = false;
155*4882a593Smuzhiyun 		rc = sja1105_vlan_filtering(ds, port, vlan_filtering, &trans);
156*4882a593Smuzhiyun 		if (rc)
157*4882a593Smuzhiyun 			break;
158*4882a593Smuzhiyun 	}
159*4882a593Smuzhiyun 	rtnl_unlock();
160*4882a593Smuzhiyun 
161*4882a593Smuzhiyun 	return rc;
162*4882a593Smuzhiyun }
163*4882a593Smuzhiyun 
164*4882a593Smuzhiyun enum sja1105_devlink_param_id {
165*4882a593Smuzhiyun 	SJA1105_DEVLINK_PARAM_ID_BASE = DEVLINK_PARAM_GENERIC_ID_MAX,
166*4882a593Smuzhiyun 	SJA1105_DEVLINK_PARAM_ID_BEST_EFFORT_VLAN_FILTERING,
167*4882a593Smuzhiyun };
168*4882a593Smuzhiyun 
sja1105_devlink_param_get(struct dsa_switch * ds,u32 id,struct devlink_param_gset_ctx * ctx)169*4882a593Smuzhiyun int sja1105_devlink_param_get(struct dsa_switch *ds, u32 id,
170*4882a593Smuzhiyun 			      struct devlink_param_gset_ctx *ctx)
171*4882a593Smuzhiyun {
172*4882a593Smuzhiyun 	struct sja1105_private *priv = ds->priv;
173*4882a593Smuzhiyun 	int err;
174*4882a593Smuzhiyun 
175*4882a593Smuzhiyun 	switch (id) {
176*4882a593Smuzhiyun 	case SJA1105_DEVLINK_PARAM_ID_BEST_EFFORT_VLAN_FILTERING:
177*4882a593Smuzhiyun 		err = sja1105_best_effort_vlan_filtering_get(priv,
178*4882a593Smuzhiyun 							     &ctx->val.vbool);
179*4882a593Smuzhiyun 		break;
180*4882a593Smuzhiyun 	default:
181*4882a593Smuzhiyun 		err = -EOPNOTSUPP;
182*4882a593Smuzhiyun 		break;
183*4882a593Smuzhiyun 	}
184*4882a593Smuzhiyun 
185*4882a593Smuzhiyun 	return err;
186*4882a593Smuzhiyun }
187*4882a593Smuzhiyun 
sja1105_devlink_param_set(struct dsa_switch * ds,u32 id,struct devlink_param_gset_ctx * ctx)188*4882a593Smuzhiyun int sja1105_devlink_param_set(struct dsa_switch *ds, u32 id,
189*4882a593Smuzhiyun 			      struct devlink_param_gset_ctx *ctx)
190*4882a593Smuzhiyun {
191*4882a593Smuzhiyun 	struct sja1105_private *priv = ds->priv;
192*4882a593Smuzhiyun 	int err;
193*4882a593Smuzhiyun 
194*4882a593Smuzhiyun 	switch (id) {
195*4882a593Smuzhiyun 	case SJA1105_DEVLINK_PARAM_ID_BEST_EFFORT_VLAN_FILTERING:
196*4882a593Smuzhiyun 		err = sja1105_best_effort_vlan_filtering_set(priv,
197*4882a593Smuzhiyun 							     ctx->val.vbool);
198*4882a593Smuzhiyun 		break;
199*4882a593Smuzhiyun 	default:
200*4882a593Smuzhiyun 		err = -EOPNOTSUPP;
201*4882a593Smuzhiyun 		break;
202*4882a593Smuzhiyun 	}
203*4882a593Smuzhiyun 
204*4882a593Smuzhiyun 	return err;
205*4882a593Smuzhiyun }
206*4882a593Smuzhiyun 
207*4882a593Smuzhiyun static const struct devlink_param sja1105_devlink_params[] = {
208*4882a593Smuzhiyun 	DSA_DEVLINK_PARAM_DRIVER(SJA1105_DEVLINK_PARAM_ID_BEST_EFFORT_VLAN_FILTERING,
209*4882a593Smuzhiyun 				 "best_effort_vlan_filtering",
210*4882a593Smuzhiyun 				 DEVLINK_PARAM_TYPE_BOOL,
211*4882a593Smuzhiyun 				 BIT(DEVLINK_PARAM_CMODE_RUNTIME)),
212*4882a593Smuzhiyun };
213*4882a593Smuzhiyun 
sja1105_setup_devlink_params(struct dsa_switch * ds)214*4882a593Smuzhiyun static int sja1105_setup_devlink_params(struct dsa_switch *ds)
215*4882a593Smuzhiyun {
216*4882a593Smuzhiyun 	return dsa_devlink_params_register(ds, sja1105_devlink_params,
217*4882a593Smuzhiyun 					   ARRAY_SIZE(sja1105_devlink_params));
218*4882a593Smuzhiyun }
219*4882a593Smuzhiyun 
sja1105_teardown_devlink_params(struct dsa_switch * ds)220*4882a593Smuzhiyun static void sja1105_teardown_devlink_params(struct dsa_switch *ds)
221*4882a593Smuzhiyun {
222*4882a593Smuzhiyun 	dsa_devlink_params_unregister(ds, sja1105_devlink_params,
223*4882a593Smuzhiyun 				      ARRAY_SIZE(sja1105_devlink_params));
224*4882a593Smuzhiyun }
225*4882a593Smuzhiyun 
sja1105_devlink_info_get(struct dsa_switch * ds,struct devlink_info_req * req,struct netlink_ext_ack * extack)226*4882a593Smuzhiyun int sja1105_devlink_info_get(struct dsa_switch *ds,
227*4882a593Smuzhiyun 			     struct devlink_info_req *req,
228*4882a593Smuzhiyun 			     struct netlink_ext_ack *extack)
229*4882a593Smuzhiyun {
230*4882a593Smuzhiyun 	struct sja1105_private *priv = ds->priv;
231*4882a593Smuzhiyun 	int rc;
232*4882a593Smuzhiyun 
233*4882a593Smuzhiyun 	rc = devlink_info_driver_name_put(req, "sja1105");
234*4882a593Smuzhiyun 	if (rc)
235*4882a593Smuzhiyun 		return rc;
236*4882a593Smuzhiyun 
237*4882a593Smuzhiyun 	rc = devlink_info_version_fixed_put(req,
238*4882a593Smuzhiyun 					    DEVLINK_INFO_VERSION_GENERIC_ASIC_ID,
239*4882a593Smuzhiyun 					    priv->info->name);
240*4882a593Smuzhiyun 	return rc;
241*4882a593Smuzhiyun }
242*4882a593Smuzhiyun 
sja1105_devlink_setup(struct dsa_switch * ds)243*4882a593Smuzhiyun int sja1105_devlink_setup(struct dsa_switch *ds)
244*4882a593Smuzhiyun {
245*4882a593Smuzhiyun 	int rc;
246*4882a593Smuzhiyun 
247*4882a593Smuzhiyun 	rc = sja1105_setup_devlink_params(ds);
248*4882a593Smuzhiyun 	if (rc)
249*4882a593Smuzhiyun 		return rc;
250*4882a593Smuzhiyun 
251*4882a593Smuzhiyun 	rc = sja1105_setup_devlink_regions(ds);
252*4882a593Smuzhiyun 	if (rc < 0) {
253*4882a593Smuzhiyun 		sja1105_teardown_devlink_params(ds);
254*4882a593Smuzhiyun 		return rc;
255*4882a593Smuzhiyun 	}
256*4882a593Smuzhiyun 
257*4882a593Smuzhiyun 	return 0;
258*4882a593Smuzhiyun }
259*4882a593Smuzhiyun 
sja1105_devlink_teardown(struct dsa_switch * ds)260*4882a593Smuzhiyun void sja1105_devlink_teardown(struct dsa_switch *ds)
261*4882a593Smuzhiyun {
262*4882a593Smuzhiyun 	sja1105_teardown_devlink_params(ds);
263*4882a593Smuzhiyun 	sja1105_teardown_devlink_regions(ds);
264*4882a593Smuzhiyun }
265