xref: /linux/net/caif/cfcnfg.c (revision d39d0ed196aa1685bb24771e92f78633c66ac9cb)
1 /*
2  * Copyright (C) ST-Ericsson AB 2010
3  * Author:	Sjur Brendeland/sjur.brandeland@stericsson.com
4  * License terms: GNU General Public License (GPL) version 2
5  */
6 #include <linux/kernel.h>
7 #include <linux/stddef.h>
8 #include <linux/slab.h>
9 #include <linux/netdevice.h>
10 #include <net/caif/caif_layer.h>
11 #include <net/caif/cfpkt.h>
12 #include <net/caif/cfcnfg.h>
13 #include <net/caif/cfctrl.h>
14 #include <net/caif/cfmuxl.h>
15 #include <net/caif/cffrml.h>
16 #include <net/caif/cfserl.h>
17 #include <net/caif/cfsrvl.h>
18 
19 #include <linux/module.h>
20 #include <asm/atomic.h>
21 
22 #define MAX_PHY_LAYERS 7
23 #define PHY_NAME_LEN 20
24 
25 #define container_obj(layr) container_of(layr, struct cfcnfg, layer)
26 #define RFM_FRAGMENT_SIZE 4030
27 
28 /* Information about CAIF physical interfaces held by Config Module in order
29  * to manage physical interfaces
30  */
31 struct cfcnfg_phyinfo {
32 	/* Pointer to the layer below the MUX (framing layer) */
33 	struct cflayer *frm_layer;
34 	/* Pointer to the lowest actual physical layer */
35 	struct cflayer *phy_layer;
36 	/* Unique identifier of the physical interface */
37 	unsigned int id;
38 	/* Preference of the physical in interface */
39 	enum cfcnfg_phy_preference pref;
40 
41 	/* Reference count, number of channels using the device */
42 	int phy_ref_count;
43 
44 	/* Information about the physical device */
45 	struct dev_info dev_info;
46 
47 	/* Interface index */
48 	int ifindex;
49 
50 	/* Use Start of frame extension */
51 	bool use_stx;
52 
53 	/* Use Start of frame checksum */
54 	bool use_fcs;
55 };
56 
57 struct cfcnfg {
58 	struct cflayer layer;
59 	struct cflayer *ctrl;
60 	struct cflayer *mux;
61 	u8 last_phyid;
62 	struct cfcnfg_phyinfo phy_layers[MAX_PHY_LAYERS];
63 };
64 
65 static void cfcnfg_linkup_rsp(struct cflayer *layer, u8 channel_id,
66 			     enum cfctrl_srv serv, u8 phyid,
67 			     struct cflayer *adapt_layer);
68 static void cfcnfg_linkdestroy_rsp(struct cflayer *layer, u8 channel_id);
69 static void cfcnfg_reject_rsp(struct cflayer *layer, u8 channel_id,
70 			     struct cflayer *adapt_layer);
71 static void cfctrl_resp_func(void);
72 static void cfctrl_enum_resp(void);
73 
74 struct cfcnfg *cfcnfg_create(void)
75 {
76 	struct cfcnfg *this;
77 	struct cfctrl_rsp *resp;
78 	/* Initiate this layer */
79 	this = kzalloc(sizeof(struct cfcnfg), GFP_ATOMIC);
80 	if (!this) {
81 		pr_warning("CAIF: %s(): Out of memory\n", __func__);
82 		return NULL;
83 	}
84 	this->mux = cfmuxl_create();
85 	if (!this->mux)
86 		goto out_of_mem;
87 	this->ctrl = cfctrl_create();
88 	if (!this->ctrl)
89 		goto out_of_mem;
90 	/* Initiate response functions */
91 	resp = cfctrl_get_respfuncs(this->ctrl);
92 	resp->enum_rsp = cfctrl_enum_resp;
93 	resp->linkerror_ind = cfctrl_resp_func;
94 	resp->linkdestroy_rsp = cfcnfg_linkdestroy_rsp;
95 	resp->sleep_rsp = cfctrl_resp_func;
96 	resp->wake_rsp = cfctrl_resp_func;
97 	resp->restart_rsp = cfctrl_resp_func;
98 	resp->radioset_rsp = cfctrl_resp_func;
99 	resp->linksetup_rsp = cfcnfg_linkup_rsp;
100 	resp->reject_rsp = cfcnfg_reject_rsp;
101 
102 	this->last_phyid = 1;
103 
104 	cfmuxl_set_uplayer(this->mux, this->ctrl, 0);
105 	layer_set_dn(this->ctrl, this->mux);
106 	layer_set_up(this->ctrl, this);
107 	return this;
108 out_of_mem:
109 	pr_warning("CAIF: %s(): Out of memory\n", __func__);
110 	kfree(this->mux);
111 	kfree(this->ctrl);
112 	kfree(this);
113 	return NULL;
114 }
115 EXPORT_SYMBOL(cfcnfg_create);
116 
117 void cfcnfg_remove(struct cfcnfg *cfg)
118 {
119 	if (cfg) {
120 		kfree(cfg->mux);
121 		kfree(cfg->ctrl);
122 		kfree(cfg);
123 	}
124 }
125 
126 static void cfctrl_resp_func(void)
127 {
128 }
129 
130 static void cfctrl_enum_resp(void)
131 {
132 }
133 
134 struct dev_info *cfcnfg_get_phyid(struct cfcnfg *cnfg,
135 				  enum cfcnfg_phy_preference phy_pref)
136 {
137 	u16 i;
138 
139 	/* Try to match with specified preference */
140 	for (i = 1; i < MAX_PHY_LAYERS; i++) {
141 		if (cnfg->phy_layers[i].id == i &&
142 		     cnfg->phy_layers[i].pref == phy_pref &&
143 		     cnfg->phy_layers[i].frm_layer != NULL) {
144 			caif_assert(cnfg->phy_layers != NULL);
145 			caif_assert(cnfg->phy_layers[i].id == i);
146 			return &cnfg->phy_layers[i].dev_info;
147 		}
148 	}
149 	/* Otherwise just return something */
150 	for (i = 1; i < MAX_PHY_LAYERS; i++) {
151 		if (cnfg->phy_layers[i].id == i) {
152 			caif_assert(cnfg->phy_layers != NULL);
153 			caif_assert(cnfg->phy_layers[i].id == i);
154 			return &cnfg->phy_layers[i].dev_info;
155 		}
156 	}
157 
158 	return NULL;
159 }
160 
161 static struct cfcnfg_phyinfo *cfcnfg_get_phyinfo(struct cfcnfg *cnfg,
162 							u8 phyid)
163 {
164 	int i;
165 	/* Try to match with specified preference */
166 	for (i = 0; i < MAX_PHY_LAYERS; i++)
167 		if (cnfg->phy_layers[i].frm_layer != NULL &&
168 		    cnfg->phy_layers[i].id == phyid)
169 			return &cnfg->phy_layers[i];
170 	return NULL;
171 }
172 
173 int cfcnfg_get_named(struct cfcnfg *cnfg, char *name)
174 {
175 	int i;
176 
177 	/* Try to match with specified name */
178 	for (i = 0; i < MAX_PHY_LAYERS; i++) {
179 		if (cnfg->phy_layers[i].frm_layer != NULL
180 		    && strcmp(cnfg->phy_layers[i].phy_layer->name,
181 			      name) == 0)
182 			return cnfg->phy_layers[i].frm_layer->id;
183 	}
184 	return 0;
185 }
186 
187 int cfcnfg_disconn_adapt_layer(struct cfcnfg *cnfg, struct cflayer *adap_layer)
188 {
189 	u8 channel_id = 0;
190 	int ret = 0;
191 	struct cflayer *servl = NULL;
192 	struct cfcnfg_phyinfo *phyinfo = NULL;
193 	u8 phyid = 0;
194 	caif_assert(adap_layer != NULL);
195 	channel_id = adap_layer->id;
196 	if (adap_layer->dn == NULL || channel_id == 0) {
197 		pr_err("CAIF: %s():adap_layer->id is 0\n", __func__);
198 		ret = -ENOTCONN;
199 		goto end;
200 	}
201 	servl = cfmuxl_remove_uplayer(cnfg->mux, channel_id);
202 	if (servl == NULL)
203 		goto end;
204 	layer_set_up(servl, NULL);
205 	ret = cfctrl_linkdown_req(cnfg->ctrl, channel_id, adap_layer);
206 	if (servl == NULL) {
207 		pr_err("CAIF: %s(): PROTOCOL ERROR "
208 		       "- Error removing service_layer Channel_Id(%d)",
209 			__func__, channel_id);
210 		ret = -EINVAL;
211 		goto end;
212 	}
213 	caif_assert(channel_id == servl->id);
214 	if (adap_layer->dn != NULL) {
215 		phyid = cfsrvl_getphyid(adap_layer->dn);
216 
217 		phyinfo = cfcnfg_get_phyinfo(cnfg, phyid);
218 		if (phyinfo == NULL) {
219 			pr_warning("CAIF: %s(): "
220 				"No interface to send disconnect to\n",
221 				__func__);
222 			ret = -ENODEV;
223 			goto end;
224 		}
225 		if (phyinfo->id != phyid ||
226 			phyinfo->phy_layer->id != phyid ||
227 			phyinfo->frm_layer->id != phyid) {
228 			pr_err("CAIF: %s(): "
229 				"Inconsistency in phy registration\n",
230 				__func__);
231 			ret = -EINVAL;
232 			goto end;
233 		}
234 	}
235 	if (phyinfo != NULL && --phyinfo->phy_ref_count == 0 &&
236 		phyinfo->phy_layer != NULL &&
237 		phyinfo->phy_layer->modemcmd != NULL) {
238 		phyinfo->phy_layer->modemcmd(phyinfo->phy_layer,
239 					     _CAIF_MODEMCMD_PHYIF_USELESS);
240 	}
241 end:
242 	cfsrvl_put(servl);
243 	cfctrl_cancel_req(cnfg->ctrl, adap_layer);
244 	if (adap_layer->ctrlcmd != NULL)
245 		adap_layer->ctrlcmd(adap_layer, CAIF_CTRLCMD_DEINIT_RSP, 0);
246 	return ret;
247 
248 }
249 EXPORT_SYMBOL(cfcnfg_disconn_adapt_layer);
250 
251 void cfcnfg_release_adap_layer(struct cflayer *adap_layer)
252 {
253 	if (adap_layer->dn)
254 		cfsrvl_put(adap_layer->dn);
255 }
256 EXPORT_SYMBOL(cfcnfg_release_adap_layer);
257 
258 static void cfcnfg_linkdestroy_rsp(struct cflayer *layer, u8 channel_id)
259 {
260 }
261 
262 int protohead[CFCTRL_SRV_MASK] = {
263 	[CFCTRL_SRV_VEI] = 4,
264 	[CFCTRL_SRV_DATAGRAM] = 7,
265 	[CFCTRL_SRV_UTIL] = 4,
266 	[CFCTRL_SRV_RFM] = 3,
267 	[CFCTRL_SRV_DBG] = 3,
268 };
269 
270 int cfcnfg_add_adaptation_layer(struct cfcnfg *cnfg,
271 				struct cfctrl_link_param *param,
272 				struct cflayer *adap_layer,
273 				int *ifindex,
274 				int *proto_head,
275 				int *proto_tail)
276 {
277 	struct cflayer *frml;
278 	if (adap_layer == NULL) {
279 		pr_err("CAIF: %s(): adap_layer is zero", __func__);
280 		return -EINVAL;
281 	}
282 	if (adap_layer->receive == NULL) {
283 		pr_err("CAIF: %s(): adap_layer->receive is NULL", __func__);
284 		return -EINVAL;
285 	}
286 	if (adap_layer->ctrlcmd == NULL) {
287 		pr_err("CAIF: %s(): adap_layer->ctrlcmd == NULL", __func__);
288 		return -EINVAL;
289 	}
290 	frml = cnfg->phy_layers[param->phyid].frm_layer;
291 	if (frml == NULL) {
292 		pr_err("CAIF: %s(): Specified PHY type does not exist!",
293 			__func__);
294 		return -ENODEV;
295 	}
296 	caif_assert(param->phyid == cnfg->phy_layers[param->phyid].id);
297 	caif_assert(cnfg->phy_layers[param->phyid].frm_layer->id ==
298 		     param->phyid);
299 	caif_assert(cnfg->phy_layers[param->phyid].phy_layer->id ==
300 		     param->phyid);
301 
302 	*ifindex = cnfg->phy_layers[param->phyid].ifindex;
303 	*proto_head =
304 		protohead[param->linktype]+
305 		(cnfg->phy_layers[param->phyid].use_stx ? 1 : 0);
306 
307 	*proto_tail = 2;
308 
309 	/* FIXME: ENUMERATE INITIALLY WHEN ACTIVATING PHYSICAL INTERFACE */
310 	cfctrl_enum_req(cnfg->ctrl, param->phyid);
311 	return cfctrl_linkup_request(cnfg->ctrl, param, adap_layer);
312 }
313 EXPORT_SYMBOL(cfcnfg_add_adaptation_layer);
314 
315 static void cfcnfg_reject_rsp(struct cflayer *layer, u8 channel_id,
316 			     struct cflayer *adapt_layer)
317 {
318 	if (adapt_layer != NULL && adapt_layer->ctrlcmd != NULL)
319 		adapt_layer->ctrlcmd(adapt_layer,
320 				     CAIF_CTRLCMD_INIT_FAIL_RSP, 0);
321 }
322 
323 static void
324 cfcnfg_linkup_rsp(struct cflayer *layer, u8 channel_id, enum cfctrl_srv serv,
325 		 u8 phyid, struct cflayer *adapt_layer)
326 {
327 	struct cfcnfg *cnfg = container_obj(layer);
328 	struct cflayer *servicel = NULL;
329 	struct cfcnfg_phyinfo *phyinfo;
330 	struct net_device *netdev;
331 
332 	if (adapt_layer == NULL) {
333 		pr_debug("CAIF: %s(): link setup response "
334 				"but no client exist, send linkdown back\n",
335 				__func__);
336 		cfctrl_linkdown_req(cnfg->ctrl, channel_id, NULL);
337 		return;
338 	}
339 
340 	caif_assert(cnfg != NULL);
341 	caif_assert(phyid != 0);
342 	phyinfo = &cnfg->phy_layers[phyid];
343 	caif_assert(phyinfo->id == phyid);
344 	caif_assert(phyinfo->phy_layer != NULL);
345 	caif_assert(phyinfo->phy_layer->id == phyid);
346 
347 	phyinfo->phy_ref_count++;
348 	if (phyinfo->phy_ref_count == 1 &&
349 	    phyinfo->phy_layer->modemcmd != NULL) {
350 		phyinfo->phy_layer->modemcmd(phyinfo->phy_layer,
351 					     _CAIF_MODEMCMD_PHYIF_USEFULL);
352 	}
353 	adapt_layer->id = channel_id;
354 
355 	switch (serv) {
356 	case CFCTRL_SRV_VEI:
357 		servicel = cfvei_create(channel_id, &phyinfo->dev_info);
358 		break;
359 	case CFCTRL_SRV_DATAGRAM:
360 		servicel = cfdgml_create(channel_id, &phyinfo->dev_info);
361 		break;
362 	case CFCTRL_SRV_RFM:
363 		netdev = phyinfo->dev_info.dev;
364 		servicel = cfrfml_create(channel_id, &phyinfo->dev_info,
365 						netdev->mtu);
366 		break;
367 	case CFCTRL_SRV_UTIL:
368 		servicel = cfutill_create(channel_id, &phyinfo->dev_info);
369 		break;
370 	case CFCTRL_SRV_VIDEO:
371 		servicel = cfvidl_create(channel_id, &phyinfo->dev_info);
372 		break;
373 	case CFCTRL_SRV_DBG:
374 		servicel = cfdbgl_create(channel_id, &phyinfo->dev_info);
375 		break;
376 	default:
377 		pr_err("CAIF: %s(): Protocol error. "
378 			"Link setup response - unknown channel type\n",
379 			__func__);
380 		return;
381 	}
382 	if (!servicel) {
383 		pr_warning("CAIF: %s(): Out of memory\n", __func__);
384 		return;
385 	}
386 	layer_set_dn(servicel, cnfg->mux);
387 	cfmuxl_set_uplayer(cnfg->mux, servicel, channel_id);
388 	layer_set_up(servicel, adapt_layer);
389 	layer_set_dn(adapt_layer, servicel);
390 	cfsrvl_get(servicel);
391 	servicel->ctrlcmd(servicel, CAIF_CTRLCMD_INIT_RSP, 0);
392 }
393 
394 void
395 cfcnfg_add_phy_layer(struct cfcnfg *cnfg, enum cfcnfg_phy_type phy_type,
396 		     struct net_device *dev, struct cflayer *phy_layer,
397 		     u16 *phyid, enum cfcnfg_phy_preference pref,
398 		     bool fcs, bool stx)
399 {
400 	struct cflayer *frml;
401 	struct cflayer *phy_driver = NULL;
402 	int i;
403 
404 
405 	if (cnfg->phy_layers[cnfg->last_phyid].frm_layer == NULL) {
406 		*phyid = cnfg->last_phyid;
407 
408 		/* range: * 1..(MAX_PHY_LAYERS-1) */
409 		cnfg->last_phyid =
410 		    (cnfg->last_phyid % (MAX_PHY_LAYERS - 1)) + 1;
411 	} else {
412 		*phyid = 0;
413 		for (i = 1; i < MAX_PHY_LAYERS; i++) {
414 			if (cnfg->phy_layers[i].frm_layer == NULL) {
415 				*phyid = i;
416 				break;
417 			}
418 		}
419 	}
420 	if (*phyid == 0) {
421 		pr_err("CAIF: %s(): No Available PHY ID\n", __func__);
422 		return;
423 	}
424 
425 	switch (phy_type) {
426 	case CFPHYTYPE_FRAG:
427 		phy_driver =
428 		    cfserl_create(CFPHYTYPE_FRAG, *phyid, stx);
429 		if (!phy_driver) {
430 			pr_warning("CAIF: %s(): Out of memory\n", __func__);
431 			return;
432 		}
433 
434 		break;
435 	case CFPHYTYPE_CAIF:
436 		phy_driver = NULL;
437 		break;
438 	default:
439 		pr_err("CAIF: %s(): %d", __func__, phy_type);
440 		return;
441 		break;
442 	}
443 
444 	phy_layer->id = *phyid;
445 	cnfg->phy_layers[*phyid].pref = pref;
446 	cnfg->phy_layers[*phyid].id = *phyid;
447 	cnfg->phy_layers[*phyid].dev_info.id = *phyid;
448 	cnfg->phy_layers[*phyid].dev_info.dev = dev;
449 	cnfg->phy_layers[*phyid].phy_layer = phy_layer;
450 	cnfg->phy_layers[*phyid].phy_ref_count = 0;
451 	cnfg->phy_layers[*phyid].ifindex = dev->ifindex;
452 	cnfg->phy_layers[*phyid].use_stx = stx;
453 	cnfg->phy_layers[*phyid].use_fcs = fcs;
454 
455 	phy_layer->type = phy_type;
456 	frml = cffrml_create(*phyid, fcs);
457 	if (!frml) {
458 		pr_warning("CAIF: %s(): Out of memory\n", __func__);
459 		return;
460 	}
461 	cnfg->phy_layers[*phyid].frm_layer = frml;
462 	cfmuxl_set_dnlayer(cnfg->mux, frml, *phyid);
463 	layer_set_up(frml, cnfg->mux);
464 
465 	if (phy_driver != NULL) {
466 		phy_driver->id = *phyid;
467 		layer_set_dn(frml, phy_driver);
468 		layer_set_up(phy_driver, frml);
469 		layer_set_dn(phy_driver, phy_layer);
470 		layer_set_up(phy_layer, phy_driver);
471 	} else {
472 		layer_set_dn(frml, phy_layer);
473 		layer_set_up(phy_layer, frml);
474 	}
475 }
476 EXPORT_SYMBOL(cfcnfg_add_phy_layer);
477 
478 int cfcnfg_del_phy_layer(struct cfcnfg *cnfg, struct cflayer *phy_layer)
479 {
480 	struct cflayer *frml, *frml_dn;
481 	u16 phyid;
482 	phyid = phy_layer->id;
483 	caif_assert(phyid == cnfg->phy_layers[phyid].id);
484 	caif_assert(phy_layer == cnfg->phy_layers[phyid].phy_layer);
485 	caif_assert(phy_layer->id == phyid);
486 	caif_assert(cnfg->phy_layers[phyid].frm_layer->id == phyid);
487 
488 	memset(&cnfg->phy_layers[phy_layer->id], 0,
489 	       sizeof(struct cfcnfg_phyinfo));
490 	frml = cfmuxl_remove_dnlayer(cnfg->mux, phy_layer->id);
491 	frml_dn = frml->dn;
492 	cffrml_set_uplayer(frml, NULL);
493 	cffrml_set_dnlayer(frml, NULL);
494 	kfree(frml);
495 
496 	if (phy_layer != frml_dn) {
497 		layer_set_up(frml_dn, NULL);
498 		layer_set_dn(frml_dn, NULL);
499 		kfree(frml_dn);
500 	}
501 	layer_set_up(phy_layer, NULL);
502 	return 0;
503 }
504 EXPORT_SYMBOL(cfcnfg_del_phy_layer);
505