cfcnfg.c 12.6 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
#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 PHY_NAME_LEN 20

#define container_obj(layr) container_of(layr, struct cfcnfg, layer)
29
#define RFM_FRAGMENT_SIZE 4030
30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48

/* 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;
49 50 51 52 53 54 55 56 57

	/* Interface index */
	int ifindex;

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

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

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

68
static void cfcnfg_linkup_rsp(struct cflayer *layer, u8 channel_id,
69 70
			     enum cfctrl_srv serv, u8 phyid,
			     struct cflayer *adapt_layer);
71
static void cfcnfg_linkdestroy_rsp(struct cflayer *layer, u8 channel_id);
72
static void cfcnfg_reject_rsp(struct cflayer *layer, u8 channel_id,
73 74 75 76 77 78 79 80 81
			     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 已提交
82
	this = kzalloc(sizeof(struct cfcnfg), GFP_ATOMIC);
83
	if (!this) {
J
Joe Perches 已提交
84
		pr_warn("Out of memory\n");
85 86 87 88 89 90 91 92 93 94 95 96
		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;
97
	resp->linkdestroy_rsp = cfcnfg_linkdestroy_rsp;
98 99 100 101
	resp->sleep_rsp = cfctrl_resp_func;
	resp->wake_rsp = cfctrl_resp_func;
	resp->restart_rsp = cfctrl_resp_func;
	resp->radioset_rsp = cfctrl_resp_func;
102 103
	resp->linksetup_rsp = cfcnfg_linkup_rsp;
	resp->reject_rsp = cfcnfg_reject_rsp;
104 105 106 107 108 109 110 111

	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 已提交
112
	pr_warn("Out of memory\n");
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 174 175
	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;
}

176 177

int cfcnfg_get_id_from_ifi(struct cfcnfg *cnfg, int ifi)
178 179
{
	int i;
180 181 182 183 184
	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;
185 186
}

187
int cfcnfg_disconn_adapt_layer(struct cfcnfg *cnfg, struct cflayer *adap_layer)
188 189 190
{
	u8 channel_id = 0;
	int ret = 0;
191
	struct cflayer *servl = NULL;
192 193 194 195
	struct cfcnfg_phyinfo *phyinfo = NULL;
	u8 phyid = 0;
	caif_assert(adap_layer != NULL);
	channel_id = adap_layer->id;
196
	if (adap_layer->dn == NULL || channel_id == 0) {
197
		pr_err("adap_layer->dn == NULL or adap_layer->id is 0\n");
198 199 200
		ret = -ENOTCONN;
		goto end;
	}
201 202
	servl = cfmuxl_remove_uplayer(cnfg->mux, channel_id);
	if (servl == NULL)
203
		goto end;
204 205 206
	layer_set_up(servl, NULL);
	ret = cfctrl_linkdown_req(cnfg->ctrl, channel_id, adap_layer);
	if (servl == NULL) {
J
Joe Perches 已提交
207 208
		pr_err("PROTOCOL ERROR - Error removing service_layer Channel_Id(%d)",
		       channel_id);
209 210 211
		ret = -EINVAL;
		goto end;
	}
212 213 214
	caif_assert(channel_id == servl->id);
	if (adap_layer->dn != NULL) {
		phyid = cfsrvl_getphyid(adap_layer->dn);
215

216 217
		phyinfo = cfcnfg_get_phyinfo(cnfg, phyid);
		if (phyinfo == NULL) {
J
Joe Perches 已提交
218
			pr_warn("No interface to send disconnect to\n");
219 220 221 222 223 224
			ret = -ENODEV;
			goto end;
		}
		if (phyinfo->id != phyid ||
			phyinfo->phy_layer->id != phyid ||
			phyinfo->frm_layer->id != phyid) {
J
Joe Perches 已提交
225
			pr_err("Inconsistency in phy registration\n");
226 227 228 229
			ret = -EINVAL;
			goto end;
		}
	}
230 231 232 233 234 235
	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);
	}
236 237 238 239 240
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);
241 242 243
	return ret;

}
244
EXPORT_SYMBOL(cfcnfg_disconn_adapt_layer);
245

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

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

257 258 259 260 261 262 263 264
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,
};

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

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

	*proto_tail = 2;

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

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

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

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

	switch (serv) {
	case CFCTRL_SRV_VEI:
349
		servicel = cfvei_create(channel_id, &phyinfo->dev_info);
350 351
		break;
	case CFCTRL_SRV_DATAGRAM:
352
		servicel = cfdgml_create(channel_id, &phyinfo->dev_info);
353 354
		break;
	case CFCTRL_SRV_RFM:
355
		netdev = phyinfo->dev_info.dev;
356
		servicel = cfrfml_create(channel_id, &phyinfo->dev_info,
357
						netdev->mtu);
358 359
		break;
	case CFCTRL_SRV_UTIL:
360
		servicel = cfutill_create(channel_id, &phyinfo->dev_info);
361 362
		break;
	case CFCTRL_SRV_VIDEO:
363
		servicel = cfvidl_create(channel_id, &phyinfo->dev_info);
364 365
		break;
	case CFCTRL_SRV_DBG:
366
		servicel = cfdbgl_create(channel_id, &phyinfo->dev_info);
367 368
		break;
	default:
J
Joe Perches 已提交
369
		pr_err("Protocol error. Link setup response - unknown channel type\n");
370 371 372
		return;
	}
	if (!servicel) {
J
Joe Perches 已提交
373
		pr_warn("Out of memory\n");
374 375 376
		return;
	}
	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
	cfsrvl_get(servicel);
381 382 383 384 385
	servicel->ctrlcmd(servicel, CAIF_CTRLCMD_INIT_RSP, 0);
}

void
cfcnfg_add_phy_layer(struct cfcnfg *cnfg, enum cfcnfg_phy_type phy_type,
386 387
		     struct net_device *dev, struct cflayer *phy_layer,
		     u16 *phyid, enum cfcnfg_phy_preference pref,
388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410
		     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 已提交
411
		pr_err("No Available PHY ID\n");
412 413 414 415 416 417 418 419
		return;
	}

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

		break;
	case CFPHYTYPE_CAIF:
		phy_driver = NULL;
		break;
	default:
J
Joe Perches 已提交
429
		pr_err("%d\n", phy_type);
430 431 432 433 434 435 436 437 438 439 440
		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;
441 442 443 444
	cnfg->phy_layers[*phyid].ifindex = dev->ifindex;
	cnfg->phy_layers[*phyid].use_stx = stx;
	cnfg->phy_layers[*phyid].use_fcs = fcs;

445 446 447
	phy_layer->type = phy_type;
	frml = cffrml_create(*phyid, fcs);
	if (!frml) {
J
Joe Perches 已提交
448
		pr_warn("Out of memory\n");
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 494
		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);