cfcnfg.c 12.5 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 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46
#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>

#include <linux/module.h>
#include <asm/atomic.h>

#define MAX_PHY_LAYERS 7

#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 {
	/* 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;

	/* Reference count, number of channels using the device */
	int phy_ref_count;

	/* Information about the physical device */
	struct dev_info dev_info;
47 48 49 50 51 52 53 54 55

	/* Interface index */
	int ifindex;

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

	/* Use Start of frame checksum */
	bool use_fcs;
56 57 58 59 60 61 62 63 64 65
};

struct cfcnfg {
	struct cflayer layer;
	struct cflayer *ctrl;
	struct cflayer *mux;
	u8 last_phyid;
	struct cfcnfg_phyinfo phy_layers[MAX_PHY_LAYERS];
};

66
static void cfcnfg_linkup_rsp(struct cflayer *layer, u8 channel_id,
67 68
			     enum cfctrl_srv serv, u8 phyid,
			     struct cflayer *adapt_layer);
69
static void cfcnfg_linkdestroy_rsp(struct cflayer *layer, u8 channel_id);
70
static void cfcnfg_reject_rsp(struct cflayer *layer, u8 channel_id,
71 72 73 74 75 76 77 78 79
			     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;
	/* 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 103 104 105 106 107 108 109

	this->last_phyid = 1;

	cfmuxl_set_uplayer(this->mux, this->ctrl, 0);
	layer_set_dn(this->ctrl, this->mux);
	layer_set_up(this->ctrl, this);
	return this;
out_of_mem:
J
Joe Perches 已提交
110
	pr_warn("Out of memory\n");
111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173
	kfree(this->mux);
	kfree(this->ctrl);
	kfree(this);
	return NULL;
}
EXPORT_SYMBOL(cfcnfg_create);

void cfcnfg_remove(struct cfcnfg *cfg)
{
	if (cfg) {
		kfree(cfg->mux);
		kfree(cfg->ctrl);
		kfree(cfg);
	}
}

static void cfctrl_resp_func(void)
{
}

static void cfctrl_enum_resp(void)
{
}

struct dev_info *cfcnfg_get_phyid(struct cfcnfg *cnfg,
				  enum cfcnfg_phy_preference phy_pref)
{
	u16 i;

	/* Try to match with specified preference */
	for (i = 1; i < MAX_PHY_LAYERS; i++) {
		if (cnfg->phy_layers[i].id == i &&
		     cnfg->phy_layers[i].pref == phy_pref &&
		     cnfg->phy_layers[i].frm_layer != NULL) {
			caif_assert(cnfg->phy_layers != NULL);
			caif_assert(cnfg->phy_layers[i].id == i);
			return &cnfg->phy_layers[i].dev_info;
		}
	}
	/* Otherwise just return something */
	for (i = 1; i < MAX_PHY_LAYERS; i++) {
		if (cnfg->phy_layers[i].id == i) {
			caif_assert(cnfg->phy_layers != NULL);
			caif_assert(cnfg->phy_layers[i].id == i);
			return &cnfg->phy_layers[i].dev_info;
		}
	}

	return NULL;
}

static struct cfcnfg_phyinfo *cfcnfg_get_phyinfo(struct cfcnfg *cnfg,
							u8 phyid)
{
	int i;
	/* Try to match with specified preference */
	for (i = 0; i < MAX_PHY_LAYERS; i++)
		if (cnfg->phy_layers[i].frm_layer != NULL &&
		    cnfg->phy_layers[i].id == phyid)
			return &cnfg->phy_layers[i];
	return NULL;
}

174 175

int cfcnfg_get_id_from_ifi(struct cfcnfg *cnfg, int ifi)
176 177
{
	int i;
178 179 180 181 182
	for (i = 0; i < MAX_PHY_LAYERS; i++)
		if (cnfg->phy_layers[i].frm_layer != NULL &&
				cnfg->phy_layers[i].ifindex == ifi)
			return i;
	return -ENODEV;
183 184
}

185
int cfcnfg_disconn_adapt_layer(struct cfcnfg *cnfg, struct cflayer *adap_layer)
186 187 188
{
	u8 channel_id = 0;
	int ret = 0;
189
	struct cflayer *servl = NULL;
190 191
	struct cfcnfg_phyinfo *phyinfo = NULL;
	u8 phyid = 0;
192

193 194
	caif_assert(adap_layer != NULL);
	channel_id = adap_layer->id;
195
	if (adap_layer->dn == NULL || channel_id == 0) {
196
		pr_err("adap_layer->dn == NULL or adap_layer->id is 0\n");
197 198 199
		ret = -ENOTCONN;
		goto end;
	}
200 201
	servl = cfmuxl_remove_uplayer(cnfg->mux, channel_id);
	if (servl == NULL) {
J
Joe Perches 已提交
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 210
	layer_set_up(servl, NULL);
	ret = cfctrl_linkdown_req(cnfg->ctrl, channel_id, adap_layer);
	if (ret)
		goto end;
211 212 213
	caif_assert(channel_id == servl->id);
	if (adap_layer->dn != NULL) {
		phyid = cfsrvl_getphyid(adap_layer->dn);
214

215 216
		phyinfo = cfcnfg_get_phyinfo(cnfg, phyid);
		if (phyinfo == NULL) {
J
Joe Perches 已提交
217
			pr_warn("No interface to send disconnect to\n");
218 219 220 221 222 223
			ret = -ENODEV;
			goto end;
		}
		if (phyinfo->id != phyid ||
			phyinfo->phy_layer->id != phyid ||
			phyinfo->frm_layer->id != phyid) {
J
Joe Perches 已提交
224
			pr_err("Inconsistency in phy registration\n");
225 226 227 228
			ret = -EINVAL;
			goto end;
		}
	}
229 230 231 232 233 234
	if (phyinfo != NULL && --phyinfo->phy_ref_count == 0 &&
		phyinfo->phy_layer != NULL &&
		phyinfo->phy_layer->modemcmd != NULL) {
		phyinfo->phy_layer->modemcmd(phyinfo->phy_layer,
					     _CAIF_MODEMCMD_PHYIF_USELESS);
	}
235 236 237 238 239
end:
	cfsrvl_put(servl);
	cfctrl_cancel_req(cnfg->ctrl, adap_layer);
	if (adap_layer->ctrlcmd != NULL)
		adap_layer->ctrlcmd(adap_layer, CAIF_CTRLCMD_DEINIT_RSP, 0);
240 241 242
	return ret;

}
243
EXPORT_SYMBOL(cfcnfg_disconn_adapt_layer);
244

245 246 247 248 249 250 251
void cfcnfg_release_adap_layer(struct cflayer *adap_layer)
{
	if (adap_layer->dn)
		cfsrvl_put(adap_layer->dn);
}
EXPORT_SYMBOL(cfcnfg_release_adap_layer);

252
static void cfcnfg_linkdestroy_rsp(struct cflayer *layer, u8 channel_id)
253 254 255
{
}

256 257 258 259 260 261 262 263
int protohead[CFCTRL_SRV_MASK] = {
	[CFCTRL_SRV_VEI] = 4,
	[CFCTRL_SRV_DATAGRAM] = 7,
	[CFCTRL_SRV_UTIL] = 4,
	[CFCTRL_SRV_RFM] = 3,
	[CFCTRL_SRV_DBG] = 3,
};

264
int cfcnfg_add_adaptation_layer(struct cfcnfg *cnfg,
265
				struct cfctrl_link_param *param,
266 267 268 269
				struct cflayer *adap_layer,
				int *ifindex,
				int *proto_head,
				int *proto_tail)
270 271 272
{
	struct cflayer *frml;
	if (adap_layer == NULL) {
J
Joe Perches 已提交
273
		pr_err("adap_layer is zero\n");
274 275 276
		return -EINVAL;
	}
	if (adap_layer->receive == NULL) {
J
Joe Perches 已提交
277
		pr_err("adap_layer->receive is NULL\n");
278 279 280
		return -EINVAL;
	}
	if (adap_layer->ctrlcmd == NULL) {
J
Joe Perches 已提交
281
		pr_err("adap_layer->ctrlcmd == NULL\n");
282 283 284 285
		return -EINVAL;
	}
	frml = cnfg->phy_layers[param->phyid].frm_layer;
	if (frml == NULL) {
J
Joe Perches 已提交
286
		pr_err("Specified PHY type does not exist!\n");
287 288 289 290 291 292 293
		return -ENODEV;
	}
	caif_assert(param->phyid == cnfg->phy_layers[param->phyid].id);
	caif_assert(cnfg->phy_layers[param->phyid].frm_layer->id ==
		     param->phyid);
	caif_assert(cnfg->phy_layers[param->phyid].phy_layer->id ==
		     param->phyid);
294 295 296 297 298 299 300 301

	*ifindex = cnfg->phy_layers[param->phyid].ifindex;
	*proto_head =
		protohead[param->linktype]+
		(cnfg->phy_layers[param->phyid].use_stx ? 1 : 0);

	*proto_tail = 2;

302 303
	/* FIXME: ENUMERATE INITIALLY WHEN ACTIVATING PHYSICAL INTERFACE */
	cfctrl_enum_req(cnfg->ctrl, param->phyid);
304
	return cfctrl_linkup_request(cnfg->ctrl, param, adap_layer);
305 306 307
}
EXPORT_SYMBOL(cfcnfg_add_adaptation_layer);

308
static void cfcnfg_reject_rsp(struct cflayer *layer, u8 channel_id,
309 310 311 312 313 314 315 316
			     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
317
cfcnfg_linkup_rsp(struct cflayer *layer, u8 channel_id, enum cfctrl_srv serv,
318 319 320 321 322
		 u8 phyid, struct cflayer *adapt_layer)
{
	struct cfcnfg *cnfg = container_obj(layer);
	struct cflayer *servicel = NULL;
	struct cfcnfg_phyinfo *phyinfo;
323 324
	struct net_device *netdev;

325
	if (adapt_layer == NULL) {
J
Joe Perches 已提交
326
		pr_debug("link setup response but no client exist, send linkdown back\n");
327
		cfctrl_linkdown_req(cnfg->ctrl, channel_id, NULL);
328 329 330 331 332 333 334 335 336 337
		return;
	}

	caif_assert(cnfg != NULL);
	caif_assert(phyid != 0);
	phyinfo = &cnfg->phy_layers[phyid];
	caif_assert(phyinfo->id == phyid);
	caif_assert(phyinfo->phy_layer != NULL);
	caif_assert(phyinfo->phy_layer->id == phyid);

338 339
	phyinfo->phy_ref_count++;
	if (phyinfo->phy_ref_count == 1 &&
340 341 342 343
	    phyinfo->phy_layer->modemcmd != NULL) {
		phyinfo->phy_layer->modemcmd(phyinfo->phy_layer,
					     _CAIF_MODEMCMD_PHYIF_USEFULL);
	}
344
	adapt_layer->id = channel_id;
345 346 347

	switch (serv) {
	case CFCTRL_SRV_VEI:
348
		servicel = cfvei_create(channel_id, &phyinfo->dev_info);
349 350
		break;
	case CFCTRL_SRV_DATAGRAM:
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:
J
Joe Perches 已提交
368
		pr_err("Protocol error. Link setup response - unknown channel type\n");
369 370 371
		return;
	}
	if (!servicel) {
J
Joe Perches 已提交
372
		pr_warn("Out of memory\n");
373 374 375
		return;
	}
	layer_set_dn(servicel, cnfg->mux);
376
	cfmuxl_set_uplayer(cnfg->mux, servicel, channel_id);
377 378
	layer_set_up(servicel, adapt_layer);
	layer_set_dn(adapt_layer, servicel);
379
	cfsrvl_get(servicel);
380 381 382 383 384
	servicel->ctrlcmd(servicel, CAIF_CTRLCMD_INIT_RSP, 0);
}

void
cfcnfg_add_phy_layer(struct cfcnfg *cnfg, enum cfcnfg_phy_type phy_type,
385 386
		     struct net_device *dev, struct cflayer *phy_layer,
		     u16 *phyid, enum cfcnfg_phy_preference pref,
387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409
		     bool fcs, bool stx)
{
	struct cflayer *frml;
	struct cflayer *phy_driver = NULL;
	int i;


	if (cnfg->phy_layers[cnfg->last_phyid].frm_layer == NULL) {
		*phyid = cnfg->last_phyid;

		/* range: * 1..(MAX_PHY_LAYERS-1) */
		cnfg->last_phyid =
		    (cnfg->last_phyid % (MAX_PHY_LAYERS - 1)) + 1;
	} else {
		*phyid = 0;
		for (i = 1; i < MAX_PHY_LAYERS; i++) {
			if (cnfg->phy_layers[i].frm_layer == NULL) {
				*phyid = i;
				break;
			}
		}
	}
	if (*phyid == 0) {
J
Joe Perches 已提交
410
		pr_err("No Available PHY ID\n");
411 412 413 414 415 416 417 418
		return;
	}

	switch (phy_type) {
	case CFPHYTYPE_FRAG:
		phy_driver =
		    cfserl_create(CFPHYTYPE_FRAG, *phyid, stx);
		if (!phy_driver) {
J
Joe Perches 已提交
419
			pr_warn("Out of memory\n");
420 421 422 423 424 425 426 427
			return;
		}

		break;
	case CFPHYTYPE_CAIF:
		phy_driver = NULL;
		break;
	default:
J
Joe Perches 已提交
428
		pr_err("%d\n", phy_type);
429 430 431 432 433 434 435 436 437 438 439
		return;
		break;
	}

	phy_layer->id = *phyid;
	cnfg->phy_layers[*phyid].pref = pref;
	cnfg->phy_layers[*phyid].id = *phyid;
	cnfg->phy_layers[*phyid].dev_info.id = *phyid;
	cnfg->phy_layers[*phyid].dev_info.dev = dev;
	cnfg->phy_layers[*phyid].phy_layer = phy_layer;
	cnfg->phy_layers[*phyid].phy_ref_count = 0;
440 441 442 443
	cnfg->phy_layers[*phyid].ifindex = dev->ifindex;
	cnfg->phy_layers[*phyid].use_stx = stx;
	cnfg->phy_layers[*phyid].use_fcs = fcs;

444 445 446
	phy_layer->type = phy_type;
	frml = cffrml_create(*phyid, fcs);
	if (!frml) {
J
Joe Perches 已提交
447
		pr_warn("Out of memory\n");
448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493
		return;
	}
	cnfg->phy_layers[*phyid].frm_layer = frml;
	cfmuxl_set_dnlayer(cnfg->mux, frml, *phyid);
	layer_set_up(frml, cnfg->mux);

	if (phy_driver != NULL) {
		phy_driver->id = *phyid;
		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);
	}
}
EXPORT_SYMBOL(cfcnfg_add_phy_layer);

int cfcnfg_del_phy_layer(struct cfcnfg *cnfg, struct cflayer *phy_layer)
{
	struct cflayer *frml, *frml_dn;
	u16 phyid;
	phyid = phy_layer->id;
	caif_assert(phyid == cnfg->phy_layers[phyid].id);
	caif_assert(phy_layer == cnfg->phy_layers[phyid].phy_layer);
	caif_assert(phy_layer->id == phyid);
	caif_assert(cnfg->phy_layers[phyid].frm_layer->id == phyid);

	memset(&cnfg->phy_layers[phy_layer->id], 0,
	       sizeof(struct cfcnfg_phyinfo));
	frml = cfmuxl_remove_dnlayer(cnfg->mux, phy_layer->id);
	frml_dn = frml->dn;
	cffrml_set_uplayer(frml, NULL);
	cffrml_set_dnlayer(frml, NULL);
	kfree(frml);

	if (phy_layer != frml_dn) {
		layer_set_up(frml_dn, NULL);
		layer_set_dn(frml_dn, NULL);
		kfree(frml_dn);
	}
	layer_set_up(phy_layer, NULL);
	return 0;
}
EXPORT_SYMBOL(cfcnfg_del_phy_layer);