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