xref: /OK3568_Linux_fs/kernel/net/caif/cfcnfg.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-only
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  * Copyright (C) ST-Ericsson AB 2010
4*4882a593Smuzhiyun  * Author:	Sjur Brendeland
5*4882a593Smuzhiyun  */
6*4882a593Smuzhiyun 
7*4882a593Smuzhiyun #define pr_fmt(fmt) KBUILD_MODNAME ":%s(): " fmt, __func__
8*4882a593Smuzhiyun 
9*4882a593Smuzhiyun #include <linux/kernel.h>
10*4882a593Smuzhiyun #include <linux/stddef.h>
11*4882a593Smuzhiyun #include <linux/slab.h>
12*4882a593Smuzhiyun #include <linux/netdevice.h>
13*4882a593Smuzhiyun #include <linux/module.h>
14*4882a593Smuzhiyun #include <net/caif/caif_layer.h>
15*4882a593Smuzhiyun #include <net/caif/cfpkt.h>
16*4882a593Smuzhiyun #include <net/caif/cfcnfg.h>
17*4882a593Smuzhiyun #include <net/caif/cfctrl.h>
18*4882a593Smuzhiyun #include <net/caif/cfmuxl.h>
19*4882a593Smuzhiyun #include <net/caif/cffrml.h>
20*4882a593Smuzhiyun #include <net/caif/cfserl.h>
21*4882a593Smuzhiyun #include <net/caif/cfsrvl.h>
22*4882a593Smuzhiyun #include <net/caif/caif_dev.h>
23*4882a593Smuzhiyun 
24*4882a593Smuzhiyun #define container_obj(layr) container_of(layr, struct cfcnfg, layer)
25*4882a593Smuzhiyun 
26*4882a593Smuzhiyun /* Information about CAIF physical interfaces held by Config Module in order
27*4882a593Smuzhiyun  * to manage physical interfaces
28*4882a593Smuzhiyun  */
29*4882a593Smuzhiyun struct cfcnfg_phyinfo {
30*4882a593Smuzhiyun 	struct list_head node;
31*4882a593Smuzhiyun 	bool up;
32*4882a593Smuzhiyun 
33*4882a593Smuzhiyun 	/* Pointer to the layer below the MUX (framing layer) */
34*4882a593Smuzhiyun 	struct cflayer *frm_layer;
35*4882a593Smuzhiyun 	/* Pointer to the lowest actual physical layer */
36*4882a593Smuzhiyun 	struct cflayer *phy_layer;
37*4882a593Smuzhiyun 	/* Unique identifier of the physical interface */
38*4882a593Smuzhiyun 	unsigned int id;
39*4882a593Smuzhiyun 	/* Preference of the physical in interface */
40*4882a593Smuzhiyun 	enum cfcnfg_phy_preference pref;
41*4882a593Smuzhiyun 
42*4882a593Smuzhiyun 	/* Information about the physical device */
43*4882a593Smuzhiyun 	struct dev_info dev_info;
44*4882a593Smuzhiyun 
45*4882a593Smuzhiyun 	/* Interface index */
46*4882a593Smuzhiyun 	int ifindex;
47*4882a593Smuzhiyun 
48*4882a593Smuzhiyun 	/* Protocol head room added for CAIF link layer */
49*4882a593Smuzhiyun 	int head_room;
50*4882a593Smuzhiyun 
51*4882a593Smuzhiyun 	/* Use Start of frame checksum */
52*4882a593Smuzhiyun 	bool use_fcs;
53*4882a593Smuzhiyun };
54*4882a593Smuzhiyun 
55*4882a593Smuzhiyun struct cfcnfg {
56*4882a593Smuzhiyun 	struct cflayer layer;
57*4882a593Smuzhiyun 	struct cflayer *ctrl;
58*4882a593Smuzhiyun 	struct cflayer *mux;
59*4882a593Smuzhiyun 	struct list_head phys;
60*4882a593Smuzhiyun 	struct mutex lock;
61*4882a593Smuzhiyun };
62*4882a593Smuzhiyun 
63*4882a593Smuzhiyun static void cfcnfg_linkup_rsp(struct cflayer *layer, u8 channel_id,
64*4882a593Smuzhiyun 			      enum cfctrl_srv serv, u8 phyid,
65*4882a593Smuzhiyun 			      struct cflayer *adapt_layer);
66*4882a593Smuzhiyun static void cfcnfg_linkdestroy_rsp(struct cflayer *layer, u8 channel_id);
67*4882a593Smuzhiyun static void cfcnfg_reject_rsp(struct cflayer *layer, u8 channel_id,
68*4882a593Smuzhiyun 			      struct cflayer *adapt_layer);
69*4882a593Smuzhiyun static void cfctrl_resp_func(void);
70*4882a593Smuzhiyun static void cfctrl_enum_resp(void);
71*4882a593Smuzhiyun 
cfcnfg_create(void)72*4882a593Smuzhiyun struct cfcnfg *cfcnfg_create(void)
73*4882a593Smuzhiyun {
74*4882a593Smuzhiyun 	struct cfcnfg *this;
75*4882a593Smuzhiyun 	struct cfctrl_rsp *resp;
76*4882a593Smuzhiyun 
77*4882a593Smuzhiyun 	might_sleep();
78*4882a593Smuzhiyun 
79*4882a593Smuzhiyun 	/* Initiate this layer */
80*4882a593Smuzhiyun 	this = kzalloc(sizeof(struct cfcnfg), GFP_ATOMIC);
81*4882a593Smuzhiyun 	if (!this)
82*4882a593Smuzhiyun 		return NULL;
83*4882a593Smuzhiyun 	this->mux = cfmuxl_create();
84*4882a593Smuzhiyun 	if (!this->mux)
85*4882a593Smuzhiyun 		goto out_of_mem;
86*4882a593Smuzhiyun 	this->ctrl = cfctrl_create();
87*4882a593Smuzhiyun 	if (!this->ctrl)
88*4882a593Smuzhiyun 		goto out_of_mem;
89*4882a593Smuzhiyun 	/* Initiate response functions */
90*4882a593Smuzhiyun 	resp = cfctrl_get_respfuncs(this->ctrl);
91*4882a593Smuzhiyun 	resp->enum_rsp = cfctrl_enum_resp;
92*4882a593Smuzhiyun 	resp->linkerror_ind = cfctrl_resp_func;
93*4882a593Smuzhiyun 	resp->linkdestroy_rsp = cfcnfg_linkdestroy_rsp;
94*4882a593Smuzhiyun 	resp->sleep_rsp = cfctrl_resp_func;
95*4882a593Smuzhiyun 	resp->wake_rsp = cfctrl_resp_func;
96*4882a593Smuzhiyun 	resp->restart_rsp = cfctrl_resp_func;
97*4882a593Smuzhiyun 	resp->radioset_rsp = cfctrl_resp_func;
98*4882a593Smuzhiyun 	resp->linksetup_rsp = cfcnfg_linkup_rsp;
99*4882a593Smuzhiyun 	resp->reject_rsp = cfcnfg_reject_rsp;
100*4882a593Smuzhiyun 	INIT_LIST_HEAD(&this->phys);
101*4882a593Smuzhiyun 
102*4882a593Smuzhiyun 	cfmuxl_set_uplayer(this->mux, this->ctrl, 0);
103*4882a593Smuzhiyun 	layer_set_dn(this->ctrl, this->mux);
104*4882a593Smuzhiyun 	layer_set_up(this->ctrl, this);
105*4882a593Smuzhiyun 	mutex_init(&this->lock);
106*4882a593Smuzhiyun 
107*4882a593Smuzhiyun 	return this;
108*4882a593Smuzhiyun out_of_mem:
109*4882a593Smuzhiyun 	synchronize_rcu();
110*4882a593Smuzhiyun 
111*4882a593Smuzhiyun 	kfree(this->mux);
112*4882a593Smuzhiyun 	kfree(this->ctrl);
113*4882a593Smuzhiyun 	kfree(this);
114*4882a593Smuzhiyun 	return NULL;
115*4882a593Smuzhiyun }
116*4882a593Smuzhiyun 
cfcnfg_remove(struct cfcnfg * cfg)117*4882a593Smuzhiyun void cfcnfg_remove(struct cfcnfg *cfg)
118*4882a593Smuzhiyun {
119*4882a593Smuzhiyun 	might_sleep();
120*4882a593Smuzhiyun 	if (cfg) {
121*4882a593Smuzhiyun 		synchronize_rcu();
122*4882a593Smuzhiyun 
123*4882a593Smuzhiyun 		kfree(cfg->mux);
124*4882a593Smuzhiyun 		cfctrl_remove(cfg->ctrl);
125*4882a593Smuzhiyun 		kfree(cfg);
126*4882a593Smuzhiyun 	}
127*4882a593Smuzhiyun }
128*4882a593Smuzhiyun 
cfctrl_resp_func(void)129*4882a593Smuzhiyun static void cfctrl_resp_func(void)
130*4882a593Smuzhiyun {
131*4882a593Smuzhiyun }
132*4882a593Smuzhiyun 
cfcnfg_get_phyinfo_rcu(struct cfcnfg * cnfg,u8 phyid)133*4882a593Smuzhiyun static struct cfcnfg_phyinfo *cfcnfg_get_phyinfo_rcu(struct cfcnfg *cnfg,
134*4882a593Smuzhiyun 						     u8 phyid)
135*4882a593Smuzhiyun {
136*4882a593Smuzhiyun 	struct cfcnfg_phyinfo *phy;
137*4882a593Smuzhiyun 
138*4882a593Smuzhiyun 	list_for_each_entry_rcu(phy, &cnfg->phys, node)
139*4882a593Smuzhiyun 		if (phy->id == phyid)
140*4882a593Smuzhiyun 			return phy;
141*4882a593Smuzhiyun 	return NULL;
142*4882a593Smuzhiyun }
143*4882a593Smuzhiyun 
cfctrl_enum_resp(void)144*4882a593Smuzhiyun static void cfctrl_enum_resp(void)
145*4882a593Smuzhiyun {
146*4882a593Smuzhiyun }
147*4882a593Smuzhiyun 
cfcnfg_get_phyid(struct cfcnfg * cnfg,enum cfcnfg_phy_preference phy_pref)148*4882a593Smuzhiyun static struct dev_info *cfcnfg_get_phyid(struct cfcnfg *cnfg,
149*4882a593Smuzhiyun 				  enum cfcnfg_phy_preference phy_pref)
150*4882a593Smuzhiyun {
151*4882a593Smuzhiyun 	/* Try to match with specified preference */
152*4882a593Smuzhiyun 	struct cfcnfg_phyinfo *phy;
153*4882a593Smuzhiyun 
154*4882a593Smuzhiyun 	list_for_each_entry_rcu(phy, &cnfg->phys, node) {
155*4882a593Smuzhiyun 		if (phy->up && phy->pref == phy_pref &&
156*4882a593Smuzhiyun 				phy->frm_layer != NULL)
157*4882a593Smuzhiyun 
158*4882a593Smuzhiyun 			return &phy->dev_info;
159*4882a593Smuzhiyun 	}
160*4882a593Smuzhiyun 
161*4882a593Smuzhiyun 	/* Otherwise just return something */
162*4882a593Smuzhiyun 	list_for_each_entry_rcu(phy, &cnfg->phys, node)
163*4882a593Smuzhiyun 		if (phy->up)
164*4882a593Smuzhiyun 			return &phy->dev_info;
165*4882a593Smuzhiyun 
166*4882a593Smuzhiyun 	return NULL;
167*4882a593Smuzhiyun }
168*4882a593Smuzhiyun 
cfcnfg_get_id_from_ifi(struct cfcnfg * cnfg,int ifi)169*4882a593Smuzhiyun static int cfcnfg_get_id_from_ifi(struct cfcnfg *cnfg, int ifi)
170*4882a593Smuzhiyun {
171*4882a593Smuzhiyun 	struct cfcnfg_phyinfo *phy;
172*4882a593Smuzhiyun 
173*4882a593Smuzhiyun 	list_for_each_entry_rcu(phy, &cnfg->phys, node)
174*4882a593Smuzhiyun 		if (phy->ifindex == ifi && phy->up)
175*4882a593Smuzhiyun 			return phy->id;
176*4882a593Smuzhiyun 	return -ENODEV;
177*4882a593Smuzhiyun }
178*4882a593Smuzhiyun 
caif_disconnect_client(struct net * net,struct cflayer * adap_layer)179*4882a593Smuzhiyun int caif_disconnect_client(struct net *net, struct cflayer *adap_layer)
180*4882a593Smuzhiyun {
181*4882a593Smuzhiyun 	u8 channel_id;
182*4882a593Smuzhiyun 	struct cfcnfg *cfg = get_cfcnfg(net);
183*4882a593Smuzhiyun 
184*4882a593Smuzhiyun 	caif_assert(adap_layer != NULL);
185*4882a593Smuzhiyun 	cfctrl_cancel_req(cfg->ctrl, adap_layer);
186*4882a593Smuzhiyun 	channel_id = adap_layer->id;
187*4882a593Smuzhiyun 	if (channel_id != 0) {
188*4882a593Smuzhiyun 		struct cflayer *servl;
189*4882a593Smuzhiyun 		servl = cfmuxl_remove_uplayer(cfg->mux, channel_id);
190*4882a593Smuzhiyun 		cfctrl_linkdown_req(cfg->ctrl, channel_id, adap_layer);
191*4882a593Smuzhiyun 		if (servl != NULL)
192*4882a593Smuzhiyun 			layer_set_up(servl, NULL);
193*4882a593Smuzhiyun 	} else
194*4882a593Smuzhiyun 		pr_debug("nothing to disconnect\n");
195*4882a593Smuzhiyun 
196*4882a593Smuzhiyun 	/* Do RCU sync before initiating cleanup */
197*4882a593Smuzhiyun 	synchronize_rcu();
198*4882a593Smuzhiyun 	if (adap_layer->ctrlcmd != NULL)
199*4882a593Smuzhiyun 		adap_layer->ctrlcmd(adap_layer, CAIF_CTRLCMD_DEINIT_RSP, 0);
200*4882a593Smuzhiyun 	return 0;
201*4882a593Smuzhiyun 
202*4882a593Smuzhiyun }
203*4882a593Smuzhiyun EXPORT_SYMBOL(caif_disconnect_client);
204*4882a593Smuzhiyun 
cfcnfg_linkdestroy_rsp(struct cflayer * layer,u8 channel_id)205*4882a593Smuzhiyun static void cfcnfg_linkdestroy_rsp(struct cflayer *layer, u8 channel_id)
206*4882a593Smuzhiyun {
207*4882a593Smuzhiyun }
208*4882a593Smuzhiyun 
209*4882a593Smuzhiyun static const int protohead[CFCTRL_SRV_MASK] = {
210*4882a593Smuzhiyun 	[CFCTRL_SRV_VEI] = 4,
211*4882a593Smuzhiyun 	[CFCTRL_SRV_DATAGRAM] = 7,
212*4882a593Smuzhiyun 	[CFCTRL_SRV_UTIL] = 4,
213*4882a593Smuzhiyun 	[CFCTRL_SRV_RFM] = 3,
214*4882a593Smuzhiyun 	[CFCTRL_SRV_DBG] = 3,
215*4882a593Smuzhiyun };
216*4882a593Smuzhiyun 
217*4882a593Smuzhiyun 
caif_connect_req_to_link_param(struct cfcnfg * cnfg,struct caif_connect_request * s,struct cfctrl_link_param * l)218*4882a593Smuzhiyun static int caif_connect_req_to_link_param(struct cfcnfg *cnfg,
219*4882a593Smuzhiyun 					  struct caif_connect_request *s,
220*4882a593Smuzhiyun 					  struct cfctrl_link_param *l)
221*4882a593Smuzhiyun {
222*4882a593Smuzhiyun 	struct dev_info *dev_info;
223*4882a593Smuzhiyun 	enum cfcnfg_phy_preference pref;
224*4882a593Smuzhiyun 	int res;
225*4882a593Smuzhiyun 
226*4882a593Smuzhiyun 	memset(l, 0, sizeof(*l));
227*4882a593Smuzhiyun 	/* In caif protocol low value is high priority */
228*4882a593Smuzhiyun 	l->priority = CAIF_PRIO_MAX - s->priority + 1;
229*4882a593Smuzhiyun 
230*4882a593Smuzhiyun 	if (s->ifindex != 0) {
231*4882a593Smuzhiyun 		res = cfcnfg_get_id_from_ifi(cnfg, s->ifindex);
232*4882a593Smuzhiyun 		if (res < 0)
233*4882a593Smuzhiyun 			return res;
234*4882a593Smuzhiyun 		l->phyid = res;
235*4882a593Smuzhiyun 	} else {
236*4882a593Smuzhiyun 		switch (s->link_selector) {
237*4882a593Smuzhiyun 		case CAIF_LINK_HIGH_BANDW:
238*4882a593Smuzhiyun 			pref = CFPHYPREF_HIGH_BW;
239*4882a593Smuzhiyun 			break;
240*4882a593Smuzhiyun 		case CAIF_LINK_LOW_LATENCY:
241*4882a593Smuzhiyun 			pref = CFPHYPREF_LOW_LAT;
242*4882a593Smuzhiyun 			break;
243*4882a593Smuzhiyun 		default:
244*4882a593Smuzhiyun 			return -EINVAL;
245*4882a593Smuzhiyun 		}
246*4882a593Smuzhiyun 		dev_info = cfcnfg_get_phyid(cnfg, pref);
247*4882a593Smuzhiyun 		if (dev_info == NULL)
248*4882a593Smuzhiyun 			return -ENODEV;
249*4882a593Smuzhiyun 		l->phyid = dev_info->id;
250*4882a593Smuzhiyun 	}
251*4882a593Smuzhiyun 	switch (s->protocol) {
252*4882a593Smuzhiyun 	case CAIFPROTO_AT:
253*4882a593Smuzhiyun 		l->linktype = CFCTRL_SRV_VEI;
254*4882a593Smuzhiyun 		l->endpoint = (s->sockaddr.u.at.type >> 2) & 0x3;
255*4882a593Smuzhiyun 		l->chtype = s->sockaddr.u.at.type & 0x3;
256*4882a593Smuzhiyun 		break;
257*4882a593Smuzhiyun 	case CAIFPROTO_DATAGRAM:
258*4882a593Smuzhiyun 		l->linktype = CFCTRL_SRV_DATAGRAM;
259*4882a593Smuzhiyun 		l->chtype = 0x00;
260*4882a593Smuzhiyun 		l->u.datagram.connid = s->sockaddr.u.dgm.connection_id;
261*4882a593Smuzhiyun 		break;
262*4882a593Smuzhiyun 	case CAIFPROTO_DATAGRAM_LOOP:
263*4882a593Smuzhiyun 		l->linktype = CFCTRL_SRV_DATAGRAM;
264*4882a593Smuzhiyun 		l->chtype = 0x03;
265*4882a593Smuzhiyun 		l->endpoint = 0x00;
266*4882a593Smuzhiyun 		l->u.datagram.connid = s->sockaddr.u.dgm.connection_id;
267*4882a593Smuzhiyun 		break;
268*4882a593Smuzhiyun 	case CAIFPROTO_RFM:
269*4882a593Smuzhiyun 		l->linktype = CFCTRL_SRV_RFM;
270*4882a593Smuzhiyun 		l->u.datagram.connid = s->sockaddr.u.rfm.connection_id;
271*4882a593Smuzhiyun 		strlcpy(l->u.rfm.volume, s->sockaddr.u.rfm.volume,
272*4882a593Smuzhiyun 			sizeof(l->u.rfm.volume));
273*4882a593Smuzhiyun 		break;
274*4882a593Smuzhiyun 	case CAIFPROTO_UTIL:
275*4882a593Smuzhiyun 		l->linktype = CFCTRL_SRV_UTIL;
276*4882a593Smuzhiyun 		l->endpoint = 0x00;
277*4882a593Smuzhiyun 		l->chtype = 0x00;
278*4882a593Smuzhiyun 		strlcpy(l->u.utility.name, s->sockaddr.u.util.service,
279*4882a593Smuzhiyun 			sizeof(l->u.utility.name));
280*4882a593Smuzhiyun 		caif_assert(sizeof(l->u.utility.name) > 10);
281*4882a593Smuzhiyun 		l->u.utility.paramlen = s->param.size;
282*4882a593Smuzhiyun 		if (l->u.utility.paramlen > sizeof(l->u.utility.params))
283*4882a593Smuzhiyun 			l->u.utility.paramlen = sizeof(l->u.utility.params);
284*4882a593Smuzhiyun 
285*4882a593Smuzhiyun 		memcpy(l->u.utility.params, s->param.data,
286*4882a593Smuzhiyun 		       l->u.utility.paramlen);
287*4882a593Smuzhiyun 
288*4882a593Smuzhiyun 		break;
289*4882a593Smuzhiyun 	case CAIFPROTO_DEBUG:
290*4882a593Smuzhiyun 		l->linktype = CFCTRL_SRV_DBG;
291*4882a593Smuzhiyun 		l->endpoint = s->sockaddr.u.dbg.service;
292*4882a593Smuzhiyun 		l->chtype = s->sockaddr.u.dbg.type;
293*4882a593Smuzhiyun 		break;
294*4882a593Smuzhiyun 	default:
295*4882a593Smuzhiyun 		return -EINVAL;
296*4882a593Smuzhiyun 	}
297*4882a593Smuzhiyun 	return 0;
298*4882a593Smuzhiyun }
299*4882a593Smuzhiyun 
caif_connect_client(struct net * net,struct caif_connect_request * conn_req,struct cflayer * adap_layer,int * ifindex,int * proto_head,int * proto_tail)300*4882a593Smuzhiyun int caif_connect_client(struct net *net, struct caif_connect_request *conn_req,
301*4882a593Smuzhiyun 			struct cflayer *adap_layer, int *ifindex,
302*4882a593Smuzhiyun 			int *proto_head, int *proto_tail)
303*4882a593Smuzhiyun {
304*4882a593Smuzhiyun 	struct cflayer *frml;
305*4882a593Smuzhiyun 	struct cfcnfg_phyinfo *phy;
306*4882a593Smuzhiyun 	int err;
307*4882a593Smuzhiyun 	struct cfctrl_link_param param;
308*4882a593Smuzhiyun 	struct cfcnfg *cfg = get_cfcnfg(net);
309*4882a593Smuzhiyun 
310*4882a593Smuzhiyun 	rcu_read_lock();
311*4882a593Smuzhiyun 	err = caif_connect_req_to_link_param(cfg, conn_req, &param);
312*4882a593Smuzhiyun 	if (err)
313*4882a593Smuzhiyun 		goto unlock;
314*4882a593Smuzhiyun 
315*4882a593Smuzhiyun 	phy = cfcnfg_get_phyinfo_rcu(cfg, param.phyid);
316*4882a593Smuzhiyun 	if (!phy) {
317*4882a593Smuzhiyun 		err = -ENODEV;
318*4882a593Smuzhiyun 		goto unlock;
319*4882a593Smuzhiyun 	}
320*4882a593Smuzhiyun 	err = -EINVAL;
321*4882a593Smuzhiyun 
322*4882a593Smuzhiyun 	if (adap_layer == NULL) {
323*4882a593Smuzhiyun 		pr_err("adap_layer is zero\n");
324*4882a593Smuzhiyun 		goto unlock;
325*4882a593Smuzhiyun 	}
326*4882a593Smuzhiyun 	if (adap_layer->receive == NULL) {
327*4882a593Smuzhiyun 		pr_err("adap_layer->receive is NULL\n");
328*4882a593Smuzhiyun 		goto unlock;
329*4882a593Smuzhiyun 	}
330*4882a593Smuzhiyun 	if (adap_layer->ctrlcmd == NULL) {
331*4882a593Smuzhiyun 		pr_err("adap_layer->ctrlcmd == NULL\n");
332*4882a593Smuzhiyun 		goto unlock;
333*4882a593Smuzhiyun 	}
334*4882a593Smuzhiyun 
335*4882a593Smuzhiyun 	err = -ENODEV;
336*4882a593Smuzhiyun 	frml = phy->frm_layer;
337*4882a593Smuzhiyun 	if (frml == NULL) {
338*4882a593Smuzhiyun 		pr_err("Specified PHY type does not exist!\n");
339*4882a593Smuzhiyun 		goto unlock;
340*4882a593Smuzhiyun 	}
341*4882a593Smuzhiyun 	caif_assert(param.phyid == phy->id);
342*4882a593Smuzhiyun 	caif_assert(phy->frm_layer->id ==
343*4882a593Smuzhiyun 		     param.phyid);
344*4882a593Smuzhiyun 	caif_assert(phy->phy_layer->id ==
345*4882a593Smuzhiyun 		     param.phyid);
346*4882a593Smuzhiyun 
347*4882a593Smuzhiyun 	*ifindex = phy->ifindex;
348*4882a593Smuzhiyun 	*proto_tail = 2;
349*4882a593Smuzhiyun 	*proto_head = protohead[param.linktype] + phy->head_room;
350*4882a593Smuzhiyun 
351*4882a593Smuzhiyun 	rcu_read_unlock();
352*4882a593Smuzhiyun 
353*4882a593Smuzhiyun 	/* FIXME: ENUMERATE INITIALLY WHEN ACTIVATING PHYSICAL INTERFACE */
354*4882a593Smuzhiyun 	cfctrl_enum_req(cfg->ctrl, param.phyid);
355*4882a593Smuzhiyun 	return cfctrl_linkup_request(cfg->ctrl, &param, adap_layer);
356*4882a593Smuzhiyun 
357*4882a593Smuzhiyun unlock:
358*4882a593Smuzhiyun 	rcu_read_unlock();
359*4882a593Smuzhiyun 	return err;
360*4882a593Smuzhiyun }
361*4882a593Smuzhiyun EXPORT_SYMBOL(caif_connect_client);
362*4882a593Smuzhiyun 
cfcnfg_reject_rsp(struct cflayer * layer,u8 channel_id,struct cflayer * adapt_layer)363*4882a593Smuzhiyun static void cfcnfg_reject_rsp(struct cflayer *layer, u8 channel_id,
364*4882a593Smuzhiyun 			      struct cflayer *adapt_layer)
365*4882a593Smuzhiyun {
366*4882a593Smuzhiyun 	if (adapt_layer != NULL && adapt_layer->ctrlcmd != NULL)
367*4882a593Smuzhiyun 		adapt_layer->ctrlcmd(adapt_layer,
368*4882a593Smuzhiyun 				     CAIF_CTRLCMD_INIT_FAIL_RSP, 0);
369*4882a593Smuzhiyun }
370*4882a593Smuzhiyun 
371*4882a593Smuzhiyun static void
cfcnfg_linkup_rsp(struct cflayer * layer,u8 channel_id,enum cfctrl_srv serv,u8 phyid,struct cflayer * adapt_layer)372*4882a593Smuzhiyun cfcnfg_linkup_rsp(struct cflayer *layer, u8 channel_id, enum cfctrl_srv serv,
373*4882a593Smuzhiyun 		  u8 phyid, struct cflayer *adapt_layer)
374*4882a593Smuzhiyun {
375*4882a593Smuzhiyun 	struct cfcnfg *cnfg = container_obj(layer);
376*4882a593Smuzhiyun 	struct cflayer *servicel = NULL;
377*4882a593Smuzhiyun 	struct cfcnfg_phyinfo *phyinfo;
378*4882a593Smuzhiyun 	struct net_device *netdev;
379*4882a593Smuzhiyun 
380*4882a593Smuzhiyun 	if (channel_id == 0) {
381*4882a593Smuzhiyun 		pr_warn("received channel_id zero\n");
382*4882a593Smuzhiyun 		if (adapt_layer != NULL && adapt_layer->ctrlcmd != NULL)
383*4882a593Smuzhiyun 			adapt_layer->ctrlcmd(adapt_layer,
384*4882a593Smuzhiyun 						CAIF_CTRLCMD_INIT_FAIL_RSP, 0);
385*4882a593Smuzhiyun 		return;
386*4882a593Smuzhiyun 	}
387*4882a593Smuzhiyun 
388*4882a593Smuzhiyun 	rcu_read_lock();
389*4882a593Smuzhiyun 
390*4882a593Smuzhiyun 	if (adapt_layer == NULL) {
391*4882a593Smuzhiyun 		pr_debug("link setup response but no client exist, send linkdown back\n");
392*4882a593Smuzhiyun 		cfctrl_linkdown_req(cnfg->ctrl, channel_id, NULL);
393*4882a593Smuzhiyun 		goto unlock;
394*4882a593Smuzhiyun 	}
395*4882a593Smuzhiyun 
396*4882a593Smuzhiyun 	caif_assert(cnfg != NULL);
397*4882a593Smuzhiyun 	caif_assert(phyid != 0);
398*4882a593Smuzhiyun 
399*4882a593Smuzhiyun 	phyinfo = cfcnfg_get_phyinfo_rcu(cnfg, phyid);
400*4882a593Smuzhiyun 	if (phyinfo == NULL) {
401*4882a593Smuzhiyun 		pr_err("ERROR: Link Layer Device disappeared while connecting\n");
402*4882a593Smuzhiyun 		goto unlock;
403*4882a593Smuzhiyun 	}
404*4882a593Smuzhiyun 
405*4882a593Smuzhiyun 	caif_assert(phyinfo != NULL);
406*4882a593Smuzhiyun 	caif_assert(phyinfo->id == phyid);
407*4882a593Smuzhiyun 	caif_assert(phyinfo->phy_layer != NULL);
408*4882a593Smuzhiyun 	caif_assert(phyinfo->phy_layer->id == phyid);
409*4882a593Smuzhiyun 
410*4882a593Smuzhiyun 	adapt_layer->id = channel_id;
411*4882a593Smuzhiyun 
412*4882a593Smuzhiyun 	switch (serv) {
413*4882a593Smuzhiyun 	case CFCTRL_SRV_VEI:
414*4882a593Smuzhiyun 		servicel = cfvei_create(channel_id, &phyinfo->dev_info);
415*4882a593Smuzhiyun 		break;
416*4882a593Smuzhiyun 	case CFCTRL_SRV_DATAGRAM:
417*4882a593Smuzhiyun 		servicel = cfdgml_create(channel_id,
418*4882a593Smuzhiyun 					&phyinfo->dev_info);
419*4882a593Smuzhiyun 		break;
420*4882a593Smuzhiyun 	case CFCTRL_SRV_RFM:
421*4882a593Smuzhiyun 		netdev = phyinfo->dev_info.dev;
422*4882a593Smuzhiyun 		servicel = cfrfml_create(channel_id, &phyinfo->dev_info,
423*4882a593Smuzhiyun 						netdev->mtu);
424*4882a593Smuzhiyun 		break;
425*4882a593Smuzhiyun 	case CFCTRL_SRV_UTIL:
426*4882a593Smuzhiyun 		servicel = cfutill_create(channel_id, &phyinfo->dev_info);
427*4882a593Smuzhiyun 		break;
428*4882a593Smuzhiyun 	case CFCTRL_SRV_VIDEO:
429*4882a593Smuzhiyun 		servicel = cfvidl_create(channel_id, &phyinfo->dev_info);
430*4882a593Smuzhiyun 		break;
431*4882a593Smuzhiyun 	case CFCTRL_SRV_DBG:
432*4882a593Smuzhiyun 		servicel = cfdbgl_create(channel_id, &phyinfo->dev_info);
433*4882a593Smuzhiyun 		break;
434*4882a593Smuzhiyun 	default:
435*4882a593Smuzhiyun 		pr_err("Protocol error. Link setup response - unknown channel type\n");
436*4882a593Smuzhiyun 		goto unlock;
437*4882a593Smuzhiyun 	}
438*4882a593Smuzhiyun 	if (!servicel)
439*4882a593Smuzhiyun 		goto unlock;
440*4882a593Smuzhiyun 	layer_set_dn(servicel, cnfg->mux);
441*4882a593Smuzhiyun 	cfmuxl_set_uplayer(cnfg->mux, servicel, channel_id);
442*4882a593Smuzhiyun 	layer_set_up(servicel, adapt_layer);
443*4882a593Smuzhiyun 	layer_set_dn(adapt_layer, servicel);
444*4882a593Smuzhiyun 
445*4882a593Smuzhiyun 	rcu_read_unlock();
446*4882a593Smuzhiyun 
447*4882a593Smuzhiyun 	servicel->ctrlcmd(servicel, CAIF_CTRLCMD_INIT_RSP, 0);
448*4882a593Smuzhiyun 	return;
449*4882a593Smuzhiyun unlock:
450*4882a593Smuzhiyun 	rcu_read_unlock();
451*4882a593Smuzhiyun }
452*4882a593Smuzhiyun 
453*4882a593Smuzhiyun int
cfcnfg_add_phy_layer(struct cfcnfg * cnfg,struct net_device * dev,struct cflayer * phy_layer,enum cfcnfg_phy_preference pref,struct cflayer * link_support,bool fcs,int head_room)454*4882a593Smuzhiyun cfcnfg_add_phy_layer(struct cfcnfg *cnfg,
455*4882a593Smuzhiyun 		     struct net_device *dev, struct cflayer *phy_layer,
456*4882a593Smuzhiyun 		     enum cfcnfg_phy_preference pref,
457*4882a593Smuzhiyun 		     struct cflayer *link_support,
458*4882a593Smuzhiyun 		     bool fcs, int head_room)
459*4882a593Smuzhiyun {
460*4882a593Smuzhiyun 	struct cflayer *frml;
461*4882a593Smuzhiyun 	struct cfcnfg_phyinfo *phyinfo = NULL;
462*4882a593Smuzhiyun 	int i, res = 0;
463*4882a593Smuzhiyun 	u8 phyid;
464*4882a593Smuzhiyun 
465*4882a593Smuzhiyun 	mutex_lock(&cnfg->lock);
466*4882a593Smuzhiyun 
467*4882a593Smuzhiyun 	/* CAIF protocol allow maximum 6 link-layers */
468*4882a593Smuzhiyun 	for (i = 0; i < 7; i++) {
469*4882a593Smuzhiyun 		phyid = (dev->ifindex + i) & 0x7;
470*4882a593Smuzhiyun 		if (phyid == 0)
471*4882a593Smuzhiyun 			continue;
472*4882a593Smuzhiyun 		if (cfcnfg_get_phyinfo_rcu(cnfg, phyid) == NULL)
473*4882a593Smuzhiyun 			goto got_phyid;
474*4882a593Smuzhiyun 	}
475*4882a593Smuzhiyun 	pr_warn("Too many CAIF Link Layers (max 6)\n");
476*4882a593Smuzhiyun 	res = -EEXIST;
477*4882a593Smuzhiyun 	goto out;
478*4882a593Smuzhiyun 
479*4882a593Smuzhiyun got_phyid:
480*4882a593Smuzhiyun 	phyinfo = kzalloc(sizeof(struct cfcnfg_phyinfo), GFP_ATOMIC);
481*4882a593Smuzhiyun 	if (!phyinfo) {
482*4882a593Smuzhiyun 		res = -ENOMEM;
483*4882a593Smuzhiyun 		goto out_err;
484*4882a593Smuzhiyun 	}
485*4882a593Smuzhiyun 
486*4882a593Smuzhiyun 	phy_layer->id = phyid;
487*4882a593Smuzhiyun 	phyinfo->pref = pref;
488*4882a593Smuzhiyun 	phyinfo->id = phyid;
489*4882a593Smuzhiyun 	phyinfo->dev_info.id = phyid;
490*4882a593Smuzhiyun 	phyinfo->dev_info.dev = dev;
491*4882a593Smuzhiyun 	phyinfo->phy_layer = phy_layer;
492*4882a593Smuzhiyun 	phyinfo->ifindex = dev->ifindex;
493*4882a593Smuzhiyun 	phyinfo->head_room = head_room;
494*4882a593Smuzhiyun 	phyinfo->use_fcs = fcs;
495*4882a593Smuzhiyun 
496*4882a593Smuzhiyun 	frml = cffrml_create(phyid, fcs);
497*4882a593Smuzhiyun 
498*4882a593Smuzhiyun 	if (!frml) {
499*4882a593Smuzhiyun 		res = -ENOMEM;
500*4882a593Smuzhiyun 		goto out_err;
501*4882a593Smuzhiyun 	}
502*4882a593Smuzhiyun 	phyinfo->frm_layer = frml;
503*4882a593Smuzhiyun 	layer_set_up(frml, cnfg->mux);
504*4882a593Smuzhiyun 
505*4882a593Smuzhiyun 	if (link_support != NULL) {
506*4882a593Smuzhiyun 		link_support->id = phyid;
507*4882a593Smuzhiyun 		layer_set_dn(frml, link_support);
508*4882a593Smuzhiyun 		layer_set_up(link_support, frml);
509*4882a593Smuzhiyun 		layer_set_dn(link_support, phy_layer);
510*4882a593Smuzhiyun 		layer_set_up(phy_layer, link_support);
511*4882a593Smuzhiyun 	} else {
512*4882a593Smuzhiyun 		layer_set_dn(frml, phy_layer);
513*4882a593Smuzhiyun 		layer_set_up(phy_layer, frml);
514*4882a593Smuzhiyun 	}
515*4882a593Smuzhiyun 
516*4882a593Smuzhiyun 	list_add_rcu(&phyinfo->node, &cnfg->phys);
517*4882a593Smuzhiyun out:
518*4882a593Smuzhiyun 	mutex_unlock(&cnfg->lock);
519*4882a593Smuzhiyun 	return res;
520*4882a593Smuzhiyun 
521*4882a593Smuzhiyun out_err:
522*4882a593Smuzhiyun 	kfree(phyinfo);
523*4882a593Smuzhiyun 	mutex_unlock(&cnfg->lock);
524*4882a593Smuzhiyun 	return res;
525*4882a593Smuzhiyun }
526*4882a593Smuzhiyun EXPORT_SYMBOL(cfcnfg_add_phy_layer);
527*4882a593Smuzhiyun 
cfcnfg_set_phy_state(struct cfcnfg * cnfg,struct cflayer * phy_layer,bool up)528*4882a593Smuzhiyun int cfcnfg_set_phy_state(struct cfcnfg *cnfg, struct cflayer *phy_layer,
529*4882a593Smuzhiyun 			 bool up)
530*4882a593Smuzhiyun {
531*4882a593Smuzhiyun 	struct cfcnfg_phyinfo *phyinfo;
532*4882a593Smuzhiyun 
533*4882a593Smuzhiyun 	rcu_read_lock();
534*4882a593Smuzhiyun 	phyinfo = cfcnfg_get_phyinfo_rcu(cnfg, phy_layer->id);
535*4882a593Smuzhiyun 	if (phyinfo == NULL) {
536*4882a593Smuzhiyun 		rcu_read_unlock();
537*4882a593Smuzhiyun 		return -ENODEV;
538*4882a593Smuzhiyun 	}
539*4882a593Smuzhiyun 
540*4882a593Smuzhiyun 	if (phyinfo->up == up) {
541*4882a593Smuzhiyun 		rcu_read_unlock();
542*4882a593Smuzhiyun 		return 0;
543*4882a593Smuzhiyun 	}
544*4882a593Smuzhiyun 	phyinfo->up = up;
545*4882a593Smuzhiyun 
546*4882a593Smuzhiyun 	if (up) {
547*4882a593Smuzhiyun 		cffrml_hold(phyinfo->frm_layer);
548*4882a593Smuzhiyun 		cfmuxl_set_dnlayer(cnfg->mux, phyinfo->frm_layer,
549*4882a593Smuzhiyun 					phy_layer->id);
550*4882a593Smuzhiyun 	} else {
551*4882a593Smuzhiyun 		cfmuxl_remove_dnlayer(cnfg->mux, phy_layer->id);
552*4882a593Smuzhiyun 		cffrml_put(phyinfo->frm_layer);
553*4882a593Smuzhiyun 	}
554*4882a593Smuzhiyun 
555*4882a593Smuzhiyun 	rcu_read_unlock();
556*4882a593Smuzhiyun 	return 0;
557*4882a593Smuzhiyun }
558*4882a593Smuzhiyun EXPORT_SYMBOL(cfcnfg_set_phy_state);
559*4882a593Smuzhiyun 
cfcnfg_del_phy_layer(struct cfcnfg * cnfg,struct cflayer * phy_layer)560*4882a593Smuzhiyun int cfcnfg_del_phy_layer(struct cfcnfg *cnfg, struct cflayer *phy_layer)
561*4882a593Smuzhiyun {
562*4882a593Smuzhiyun 	struct cflayer *frml, *frml_dn;
563*4882a593Smuzhiyun 	u16 phyid;
564*4882a593Smuzhiyun 	struct cfcnfg_phyinfo *phyinfo;
565*4882a593Smuzhiyun 
566*4882a593Smuzhiyun 	might_sleep();
567*4882a593Smuzhiyun 
568*4882a593Smuzhiyun 	mutex_lock(&cnfg->lock);
569*4882a593Smuzhiyun 
570*4882a593Smuzhiyun 	phyid = phy_layer->id;
571*4882a593Smuzhiyun 	phyinfo = cfcnfg_get_phyinfo_rcu(cnfg, phyid);
572*4882a593Smuzhiyun 
573*4882a593Smuzhiyun 	if (phyinfo == NULL) {
574*4882a593Smuzhiyun 		mutex_unlock(&cnfg->lock);
575*4882a593Smuzhiyun 		return 0;
576*4882a593Smuzhiyun 	}
577*4882a593Smuzhiyun 	caif_assert(phyid == phyinfo->id);
578*4882a593Smuzhiyun 	caif_assert(phy_layer == phyinfo->phy_layer);
579*4882a593Smuzhiyun 	caif_assert(phy_layer->id == phyid);
580*4882a593Smuzhiyun 	caif_assert(phyinfo->frm_layer->id == phyid);
581*4882a593Smuzhiyun 
582*4882a593Smuzhiyun 	list_del_rcu(&phyinfo->node);
583*4882a593Smuzhiyun 	synchronize_rcu();
584*4882a593Smuzhiyun 
585*4882a593Smuzhiyun 	/* Fail if reference count is not zero */
586*4882a593Smuzhiyun 	if (cffrml_refcnt_read(phyinfo->frm_layer) != 0) {
587*4882a593Smuzhiyun 		pr_info("Wait for device inuse\n");
588*4882a593Smuzhiyun 		list_add_rcu(&phyinfo->node, &cnfg->phys);
589*4882a593Smuzhiyun 		mutex_unlock(&cnfg->lock);
590*4882a593Smuzhiyun 		return -EAGAIN;
591*4882a593Smuzhiyun 	}
592*4882a593Smuzhiyun 
593*4882a593Smuzhiyun 	frml = phyinfo->frm_layer;
594*4882a593Smuzhiyun 	frml_dn = frml->dn;
595*4882a593Smuzhiyun 	cffrml_set_uplayer(frml, NULL);
596*4882a593Smuzhiyun 	cffrml_set_dnlayer(frml, NULL);
597*4882a593Smuzhiyun 	if (phy_layer != frml_dn) {
598*4882a593Smuzhiyun 		layer_set_up(frml_dn, NULL);
599*4882a593Smuzhiyun 		layer_set_dn(frml_dn, NULL);
600*4882a593Smuzhiyun 	}
601*4882a593Smuzhiyun 	layer_set_up(phy_layer, NULL);
602*4882a593Smuzhiyun 
603*4882a593Smuzhiyun 	if (phyinfo->phy_layer != frml_dn)
604*4882a593Smuzhiyun 		kfree(frml_dn);
605*4882a593Smuzhiyun 
606*4882a593Smuzhiyun 	cffrml_free(frml);
607*4882a593Smuzhiyun 	kfree(phyinfo);
608*4882a593Smuzhiyun 	mutex_unlock(&cnfg->lock);
609*4882a593Smuzhiyun 
610*4882a593Smuzhiyun 	return 0;
611*4882a593Smuzhiyun }
612*4882a593Smuzhiyun EXPORT_SYMBOL(cfcnfg_del_phy_layer);
613