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, ¶m);
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, ¶m, 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