cfcnfg.c 12.4 KB
Newer Older
1 2 3 4 5
/*
 * Copyright (C) ST-Ericsson AB 2010
 * Author:	Sjur Brendeland/sjur.brandeland@stericsson.com
 * License terms: GNU General Public License (GPL) version 2
 */
J
Joe Perches 已提交
6 7 8

#define pr_fmt(fmt) KBUILD_MODNAME ":%s(): " fmt, __func__

9 10
#include <linux/kernel.h>
#include <linux/stddef.h>
11
#include <linux/slab.h>
12
#include <linux/netdevice.h>
13
#include <linux/module.h>
14 15 16 17 18 19 20 21
#include <net/caif/caif_layer.h>
#include <net/caif/cfpkt.h>
#include <net/caif/cfcnfg.h>
#include <net/caif/cfctrl.h>
#include <net/caif/cfmuxl.h>
#include <net/caif/cffrml.h>
#include <net/caif/cfserl.h>
#include <net/caif/cfsrvl.h>
22
#include <net/caif/caif_dev.h>
23 24 25 26 27 28 29

#define container_obj(layr) container_of(layr, struct cfcnfg, layer)

/* Information about CAIF physical interfaces held by Config Module in order
 * to manage physical interfaces
 */
struct cfcnfg_phyinfo {
30 31 32
	struct list_head node;
	bool up;

33 34 35 36 37 38 39 40 41 42 43
	/* Pointer to the layer below the MUX (framing layer) */
	struct cflayer *frm_layer;
	/* Pointer to the lowest actual physical layer */
	struct cflayer *phy_layer;
	/* Unique identifier of the physical interface */
	unsigned int id;
	/* Preference of the physical in interface */
	enum cfcnfg_phy_preference pref;

	/* Information about the physical device */
	struct dev_info dev_info;
44 45 46 47 48 49 50 51 52

	/* Interface index */
	int ifindex;

	/* Use Start of frame extension */
	bool use_stx;

	/* Use Start of frame checksum */
	bool use_fcs;
53 54 55 56 57 58
};

struct cfcnfg {
	struct cflayer layer;
	struct cflayer *ctrl;
	struct cflayer *mux;
59 60
	struct list_head phys;
	struct mutex lock;
61 62
};

63
static void cfcnfg_linkup_rsp(struct cflayer *layer, u8 channel_id,
64 65
			     enum cfctrl_srv serv, u8 phyid,
			     struct cflayer *adapt_layer);
66
static void cfcnfg_linkdestroy_rsp(struct cflayer *layer, u8 channel_id);
67
static void cfcnfg_reject_rsp(struct cflayer *layer, u8 channel_id,
68 69 70 71 72 73 74 75
			     struct cflayer *adapt_layer);
static void cfctrl_resp_func(void);
static void cfctrl_enum_resp(void);

struct cfcnfg *cfcnfg_create(void)
{
	struct cfcnfg *this;
	struct cfctrl_rsp *resp;
76 77 78

	might_sleep();

79
	/* Initiate this layer */
J
Julia Lawall 已提交
80
	this = kzalloc(sizeof(struct cfcnfg), GFP_ATOMIC);
81
	if (!this) {
J
Joe Perches 已提交
82
		pr_warn("Out of memory\n");
83 84 85 86 87 88 89 90 91 92 93 94
		return NULL;
	}
	this->mux = cfmuxl_create();
	if (!this->mux)
		goto out_of_mem;
	this->ctrl = cfctrl_create();
	if (!this->ctrl)
		goto out_of_mem;
	/* Initiate response functions */
	resp = cfctrl_get_respfuncs(this->ctrl);
	resp->enum_rsp = cfctrl_enum_resp;
	resp->linkerror_ind = cfctrl_resp_func;
95
	resp->linkdestroy_rsp = cfcnfg_linkdestroy_rsp;
96 97 98 99
	resp->sleep_rsp = cfctrl_resp_func;
	resp->wake_rsp = cfctrl_resp_func;
	resp->restart_rsp = cfctrl_resp_func;
	resp->radioset_rsp = cfctrl_resp_func;
100 101
	resp->linksetup_rsp = cfcnfg_linkup_rsp;
	resp->reject_rsp = cfcnfg_reject_rsp;
102
	INIT_LIST_HEAD(&this->phys);
103 104 105 106

	cfmuxl_set_uplayer(this->mux, this->ctrl, 0);
	layer_set_dn(this->ctrl, this->mux);
	layer_set_up(this->ctrl, this);
107 108
	mutex_init(&this->lock);

109 110
	return this;
out_of_mem:
J
Joe Perches 已提交
111
	pr_warn("Out of memory\n");
112 113 114

	synchronize_rcu();

115 116 117 118 119 120 121 122 123
	kfree(this->mux);
	kfree(this->ctrl);
	kfree(this);
	return NULL;
}
EXPORT_SYMBOL(cfcnfg_create);

void cfcnfg_remove(struct cfcnfg *cfg)
{
124
	might_sleep();
125
	if (cfg) {
126 127
		synchronize_rcu();

128 129 130 131 132 133 134 135 136 137
		kfree(cfg->mux);
		kfree(cfg->ctrl);
		kfree(cfg);
	}
}

static void cfctrl_resp_func(void)
{
}

138 139 140 141 142 143 144 145 146 147 148
static struct cfcnfg_phyinfo *cfcnfg_get_phyinfo_rcu(struct cfcnfg *cnfg,
							u8 phyid)
{
	struct cfcnfg_phyinfo *phy;

	list_for_each_entry_rcu(phy, &cnfg->phys, node)
		if (phy->id == phyid)
			return phy;
	return NULL;
}

149 150 151 152 153 154 155 156
static void cfctrl_enum_resp(void)
{
}

struct dev_info *cfcnfg_get_phyid(struct cfcnfg *cnfg,
				  enum cfcnfg_phy_preference phy_pref)
{
	/* Try to match with specified preference */
157 158 159 160 161 162 163
	struct cfcnfg_phyinfo *phy;

	list_for_each_entry_rcu(phy, &cnfg->phys, node) {
		if (phy->up && phy->pref == phy_pref &&
				phy->frm_layer != NULL)

			return &phy->dev_info;
164 165
	}

166 167 168 169
	/* Otherwise just return something */
	list_for_each_entry_rcu(phy, &cnfg->phys, node)
		if (phy->up)
			return &phy->dev_info;
170 171 172 173

	return NULL;
}

174
int cfcnfg_get_id_from_ifi(struct cfcnfg *cnfg, int ifi)
175
{
176 177 178 179 180
	struct cfcnfg_phyinfo *phy;

	list_for_each_entry_rcu(phy, &cnfg->phys, node)
		if (phy->ifindex == ifi && phy->up)
			return phy->id;
181
	return -ENODEV;
182 183
}

184
int cfcnfg_disconn_adapt_layer(struct cfcnfg *cfg, struct cflayer *adap_layer)
185 186 187
{
	u8 channel_id = 0;
	int ret = 0;
188
	struct cflayer *servl = NULL;
189

190
	caif_assert(adap_layer != NULL);
191

192
	channel_id = adap_layer->id;
193
	if (adap_layer->dn == NULL || channel_id == 0) {
194
		pr_err("adap_layer->dn == NULL or adap_layer->id is 0\n");
195 196 197
		ret = -ENOTCONN;
		goto end;
	}
198 199

	servl = cfmuxl_remove_uplayer(cfg->mux, channel_id);
200
	if (servl == NULL) {
201 202 203
		pr_err("PROTOCOL ERROR - "
				"Error removing service_layer Channel_Id(%d)",
				channel_id);
204 205 206
		ret = -EINVAL;
		goto end;
	}
207 208 209

	ret = cfctrl_linkdown_req(cfg->ctrl, channel_id, adap_layer);

210
end:
211 212 213 214
	cfctrl_cancel_req(cfg->ctrl, adap_layer);

	/* Do RCU sync before initiating cleanup */
	synchronize_rcu();
215 216
	if (adap_layer->ctrlcmd != NULL)
		adap_layer->ctrlcmd(adap_layer, CAIF_CTRLCMD_DEINIT_RSP, 0);
217 218 219
	return ret;

}
220
EXPORT_SYMBOL(cfcnfg_disconn_adapt_layer);
221

222 223 224 225 226 227 228
void cfcnfg_release_adap_layer(struct cflayer *adap_layer)
{
	if (adap_layer->dn)
		cfsrvl_put(adap_layer->dn);
}
EXPORT_SYMBOL(cfcnfg_release_adap_layer);

229
static void cfcnfg_linkdestroy_rsp(struct cflayer *layer, u8 channel_id)
230 231 232
{
}

S
Stephen Hemminger 已提交
233
static const int protohead[CFCTRL_SRV_MASK] = {
234 235 236 237 238 239 240
	[CFCTRL_SRV_VEI] = 4,
	[CFCTRL_SRV_DATAGRAM] = 7,
	[CFCTRL_SRV_UTIL] = 4,
	[CFCTRL_SRV_RFM] = 3,
	[CFCTRL_SRV_DBG] = 3,
};

241
int cfcnfg_add_adaptation_layer(struct cfcnfg *cnfg,
242
				struct cfctrl_link_param *param,
243 244 245 246
				struct cflayer *adap_layer,
				int *ifindex,
				int *proto_head,
				int *proto_tail)
247 248
{
	struct cflayer *frml;
249 250 251 252 253 254 255 256 257 258 259
	struct cfcnfg_phyinfo *phy;
	int err;

	rcu_read_lock();
	phy = cfcnfg_get_phyinfo_rcu(cnfg, param->phyid);
	if (!phy) {
		err = -ENODEV;
		goto unlock;
	}
	err = -EINVAL;

260
	if (adap_layer == NULL) {
J
Joe Perches 已提交
261
		pr_err("adap_layer is zero\n");
262
		goto unlock;
263 264
	}
	if (adap_layer->receive == NULL) {
J
Joe Perches 已提交
265
		pr_err("adap_layer->receive is NULL\n");
266
		goto unlock;
267 268
	}
	if (adap_layer->ctrlcmd == NULL) {
J
Joe Perches 已提交
269
		pr_err("adap_layer->ctrlcmd == NULL\n");
270
		goto unlock;
271
	}
272 273 274

	err = -ENODEV;
	frml = phy->frm_layer;
275
	if (frml == NULL) {
J
Joe Perches 已提交
276
		pr_err("Specified PHY type does not exist!\n");
277
		goto unlock;
278
	}
279 280
	caif_assert(param->phyid == phy->id);
	caif_assert(phy->frm_layer->id ==
281
		     param->phyid);
282
	caif_assert(phy->phy_layer->id ==
283
		     param->phyid);
284

285 286
	*ifindex = phy->ifindex;
	*proto_tail = 2;
287
	*proto_head =
288
		protohead[param->linktype] + (phy->use_stx ? 1 : 0);
289

290
	rcu_read_unlock();
291

292 293
	/* FIXME: ENUMERATE INITIALLY WHEN ACTIVATING PHYSICAL INTERFACE */
	cfctrl_enum_req(cnfg->ctrl, param->phyid);
294
	return cfctrl_linkup_request(cnfg->ctrl, param, adap_layer);
295 296 297 298

unlock:
	rcu_read_unlock();
	return err;
299 300 301
}
EXPORT_SYMBOL(cfcnfg_add_adaptation_layer);

302
static void cfcnfg_reject_rsp(struct cflayer *layer, u8 channel_id,
303 304 305 306 307 308 309 310
			     struct cflayer *adapt_layer)
{
	if (adapt_layer != NULL && adapt_layer->ctrlcmd != NULL)
		adapt_layer->ctrlcmd(adapt_layer,
				     CAIF_CTRLCMD_INIT_FAIL_RSP, 0);
}

static void
311
cfcnfg_linkup_rsp(struct cflayer *layer, u8 channel_id, enum cfctrl_srv serv,
312
		  u8 phyid, struct cflayer *adapt_layer)
313 314 315 316
{
	struct cfcnfg *cnfg = container_obj(layer);
	struct cflayer *servicel = NULL;
	struct cfcnfg_phyinfo *phyinfo;
317 318
	struct net_device *netdev;

319 320
	rcu_read_lock();

321
	if (adapt_layer == NULL) {
322 323
		pr_debug("link setup response but no client exist,"
				"send linkdown back\n");
324
		cfctrl_linkdown_req(cnfg->ctrl, channel_id, NULL);
325
		goto unlock;
326 327 328 329
	}

	caif_assert(cnfg != NULL);
	caif_assert(phyid != 0);
330 331 332 333 334 335 336 337 338

	phyinfo = cfcnfg_get_phyinfo_rcu(cnfg, phyid);
	if (phyinfo == NULL) {
		pr_err("ERROR: Link Layer Device dissapeared"
				"while connecting\n");
		goto unlock;
	}

	caif_assert(phyinfo != NULL);
339 340 341 342
	caif_assert(phyinfo->id == phyid);
	caif_assert(phyinfo->phy_layer != NULL);
	caif_assert(phyinfo->phy_layer->id == phyid);

343
	adapt_layer->id = channel_id;
344 345 346

	switch (serv) {
	case CFCTRL_SRV_VEI:
347
		servicel = cfvei_create(channel_id, &phyinfo->dev_info);
348 349
		break;
	case CFCTRL_SRV_DATAGRAM:
350 351
		servicel = cfdgml_create(channel_id,
					&phyinfo->dev_info);
352 353
		break;
	case CFCTRL_SRV_RFM:
354
		netdev = phyinfo->dev_info.dev;
355
		servicel = cfrfml_create(channel_id, &phyinfo->dev_info,
356
						netdev->mtu);
357 358
		break;
	case CFCTRL_SRV_UTIL:
359
		servicel = cfutill_create(channel_id, &phyinfo->dev_info);
360 361
		break;
	case CFCTRL_SRV_VIDEO:
362
		servicel = cfvidl_create(channel_id, &phyinfo->dev_info);
363 364
		break;
	case CFCTRL_SRV_DBG:
365
		servicel = cfdbgl_create(channel_id, &phyinfo->dev_info);
366 367
		break;
	default:
368 369 370
		pr_err("Protocol error. Link setup response "
				"- unknown channel type\n");
		goto unlock;
371 372
	}
	if (!servicel) {
J
Joe Perches 已提交
373
		pr_warn("Out of memory\n");
374
		goto unlock;
375 376
	}
	layer_set_dn(servicel, cnfg->mux);
377
	cfmuxl_set_uplayer(cnfg->mux, servicel, channel_id);
378 379
	layer_set_up(servicel, adapt_layer);
	layer_set_dn(adapt_layer, servicel);
380 381 382

	rcu_read_unlock();

383
	servicel->ctrlcmd(servicel, CAIF_CTRLCMD_INIT_RSP, 0);
384 385 386
	return;
unlock:
	rcu_read_unlock();
387 388 389 390
}

void
cfcnfg_add_phy_layer(struct cfcnfg *cnfg, enum cfcnfg_phy_type phy_type,
391
		     struct net_device *dev, struct cflayer *phy_layer,
392
		     u16 *phy_id, enum cfcnfg_phy_preference pref,
393 394 395 396
		     bool fcs, bool stx)
{
	struct cflayer *frml;
	struct cflayer *phy_driver = NULL;
397
	struct cfcnfg_phyinfo *phyinfo;
398
	int i;
399
	u8 phyid;
400

401
	mutex_lock(&cnfg->lock);
402

403 404 405 406 407 408 409
	/* CAIF protocol allow maximum 6 link-layers */
	for (i = 0; i < 7; i++) {
		phyid = (dev->ifindex + i) & 0x7;
		if (phyid == 0)
			continue;
		if (cfcnfg_get_phyinfo_rcu(cnfg, phyid) == NULL)
			goto got_phyid;
410
	}
411 412 413 414 415
	pr_warn("Too many CAIF Link Layers (max 6)\n");
	goto out;

got_phyid:
	phyinfo = kzalloc(sizeof(struct cfcnfg_phyinfo), GFP_ATOMIC);
416 417 418 419

	switch (phy_type) {
	case CFPHYTYPE_FRAG:
		phy_driver =
420
		    cfserl_create(CFPHYTYPE_FRAG, phyid, stx);
421
		if (!phy_driver) {
J
Joe Perches 已提交
422
			pr_warn("Out of memory\n");
423
			goto out;
424 425 426 427 428 429
		}
		break;
	case CFPHYTYPE_CAIF:
		phy_driver = NULL;
		break;
	default:
430
		goto out;
431
	}
432 433 434 435 436 437 438 439 440
	phy_layer->id = phyid;
	phyinfo->pref = pref;
	phyinfo->id = phyid;
	phyinfo->dev_info.id = phyid;
	phyinfo->dev_info.dev = dev;
	phyinfo->phy_layer = phy_layer;
	phyinfo->ifindex = dev->ifindex;
	phyinfo->use_stx = stx;
	phyinfo->use_fcs = fcs;
441

442
	phy_layer->type = phy_type;
443 444
	frml = cffrml_create(phyid, fcs);

445
	if (!frml) {
J
Joe Perches 已提交
446
		pr_warn("Out of memory\n");
447 448
		kfree(phyinfo);
		goto out;
449
	}
450
	phyinfo->frm_layer = frml;
451 452 453
	layer_set_up(frml, cnfg->mux);

	if (phy_driver != NULL) {
454
		phy_driver->id = phyid;
455 456 457 458 459 460 461 462
		layer_set_dn(frml, phy_driver);
		layer_set_up(phy_driver, frml);
		layer_set_dn(phy_driver, phy_layer);
		layer_set_up(phy_layer, phy_driver);
	} else {
		layer_set_dn(frml, phy_layer);
		layer_set_up(phy_layer, frml);
	}
463 464 465 466

	list_add_rcu(&phyinfo->node, &cnfg->phys);
out:
	mutex_unlock(&cnfg->lock);
467 468 469
}
EXPORT_SYMBOL(cfcnfg_add_phy_layer);

470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501
int cfcnfg_set_phy_state(struct cfcnfg *cnfg, struct cflayer *phy_layer,
		bool up)
{
	struct cfcnfg_phyinfo *phyinfo;

	rcu_read_lock();
	phyinfo = cfcnfg_get_phyinfo_rcu(cnfg, phy_layer->id);
	if (phyinfo == NULL) {
		rcu_read_unlock();
		return -ENODEV;
	}

	if (phyinfo->up == up) {
		rcu_read_unlock();
		return 0;
	}
	phyinfo->up = up;

	if (up) {
		cffrml_hold(phyinfo->frm_layer);
		cfmuxl_set_dnlayer(cnfg->mux, phyinfo->frm_layer,
					phy_layer->id);
	} else {
		cfmuxl_remove_dnlayer(cnfg->mux, phy_layer->id);
		cffrml_put(phyinfo->frm_layer);
	}

	rcu_read_unlock();
	return 0;
}
EXPORT_SYMBOL(cfcnfg_set_phy_state);

502 503 504 505
int cfcnfg_del_phy_layer(struct cfcnfg *cnfg, struct cflayer *phy_layer)
{
	struct cflayer *frml, *frml_dn;
	u16 phyid;
506 507 508 509 510 511
	struct cfcnfg_phyinfo *phyinfo;

	might_sleep();

	mutex_lock(&cnfg->lock);

512
	phyid = phy_layer->id;
513 514 515 516 517 518
	phyinfo = cfcnfg_get_phyinfo_rcu(cnfg, phyid);

	if (phyinfo == NULL)
		return 0;
	caif_assert(phyid == phyinfo->id);
	caif_assert(phy_layer == phyinfo->phy_layer);
519
	caif_assert(phy_layer->id == phyid);
520 521
	caif_assert(phyinfo->frm_layer->id == phyid);

522 523 524 525 526 527 528
	/* Fail if reference count is not zero */
	if (cffrml_refcnt_read(phyinfo->frm_layer) != 0) {
		pr_info("Wait for device inuse\n");
		mutex_unlock(&cnfg->lock);
		return -EAGAIN;
	}

529 530
	list_del_rcu(&phyinfo->node);
	synchronize_rcu();
531

532
	frml = phyinfo->frm_layer;
533 534 535 536 537 538 539 540
	frml_dn = frml->dn;
	cffrml_set_uplayer(frml, NULL);
	cffrml_set_dnlayer(frml, NULL);
	if (phy_layer != frml_dn) {
		layer_set_up(frml_dn, NULL);
		layer_set_dn(frml_dn, NULL);
	}
	layer_set_up(phy_layer, NULL);
541 542 543 544 545 546



	if (phyinfo->phy_layer != frml_dn)
		kfree(frml_dn);

547
	cffrml_free(frml);
548 549 550
	kfree(phyinfo);
	mutex_unlock(&cnfg->lock);

551 552 553
	return 0;
}
EXPORT_SYMBOL(cfcnfg_del_phy_layer);