xref: /openbmc/linux/net/caif/cfsrvl.c (revision cbecf716ca618fd44feda6bd9a64a8179d031fc5)
1*af873fceSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
2b482cd20SSjur Braendeland /*
3b482cd20SSjur Braendeland  * Copyright (C) ST-Ericsson AB 2010
426ee65e6Ssjur.brandeland@stericsson.com  * Author:	Sjur Brendeland
5b482cd20SSjur Braendeland  */
6b482cd20SSjur Braendeland 
7b31fa5baSJoe Perches #define pr_fmt(fmt) KBUILD_MODNAME ":%s(): " fmt, __func__
8b31fa5baSJoe Perches 
9b482cd20SSjur Braendeland #include <linux/kernel.h>
10b482cd20SSjur Braendeland #include <linux/types.h>
11b482cd20SSjur Braendeland #include <linux/errno.h>
12b482cd20SSjur Braendeland #include <linux/slab.h>
1343e36921Ssjur.brandeland@stericsson.com #include <linux/module.h>
1444764812SDmitry Tarnyagin #include <linux/pkt_sched.h>
15b482cd20SSjur Braendeland #include <net/caif/caif_layer.h>
16b482cd20SSjur Braendeland #include <net/caif/cfsrvl.h>
17b482cd20SSjur Braendeland #include <net/caif/cfpkt.h>
1802fe72c9SRashika Kheria #include <net/caif/caif_dev.h>
19b482cd20SSjur Braendeland 
20b482cd20SSjur Braendeland #define SRVL_CTRL_PKT_SIZE 1
21b482cd20SSjur Braendeland #define SRVL_FLOW_OFF 0x81
22b482cd20SSjur Braendeland #define SRVL_FLOW_ON  0x80
23b482cd20SSjur Braendeland #define SRVL_SET_PIN  0x82
24b482cd20SSjur Braendeland 
25b482cd20SSjur Braendeland #define container_obj(layr) container_of(layr, struct cfsrvl, layer)
26b482cd20SSjur Braendeland 
cfservl_ctrlcmd(struct cflayer * layr,enum caif_ctrlcmd ctrl,int phyid)27b482cd20SSjur Braendeland static void cfservl_ctrlcmd(struct cflayer *layr, enum caif_ctrlcmd ctrl,
28b482cd20SSjur Braendeland 			    int phyid)
29b482cd20SSjur Braendeland {
30b482cd20SSjur Braendeland 	struct cfsrvl *service = container_obj(layr);
31b1c74247SSjur Braendeland 
3243e36921Ssjur.brandeland@stericsson.com 	if (layr->up == NULL || layr->up->ctrlcmd == NULL)
3343e36921Ssjur.brandeland@stericsson.com 		return;
34b1c74247SSjur Braendeland 
35b482cd20SSjur Braendeland 	switch (ctrl) {
36b482cd20SSjur Braendeland 	case CAIF_CTRLCMD_INIT_RSP:
37b482cd20SSjur Braendeland 		service->open = true;
38b482cd20SSjur Braendeland 		layr->up->ctrlcmd(layr->up, ctrl, phyid);
39b482cd20SSjur Braendeland 		break;
40b482cd20SSjur Braendeland 	case CAIF_CTRLCMD_DEINIT_RSP:
41b482cd20SSjur Braendeland 	case CAIF_CTRLCMD_INIT_FAIL_RSP:
42b482cd20SSjur Braendeland 		service->open = false;
43b482cd20SSjur Braendeland 		layr->up->ctrlcmd(layr->up, ctrl, phyid);
44b482cd20SSjur Braendeland 		break;
45b482cd20SSjur Braendeland 	case _CAIF_CTRLCMD_PHYIF_FLOW_OFF_IND:
46b482cd20SSjur Braendeland 		if (phyid != service->dev_info.id)
47b482cd20SSjur Braendeland 			break;
48b482cd20SSjur Braendeland 		if (service->modem_flow_on)
49b482cd20SSjur Braendeland 			layr->up->ctrlcmd(layr->up,
50b482cd20SSjur Braendeland 					  CAIF_CTRLCMD_FLOW_OFF_IND, phyid);
51b482cd20SSjur Braendeland 		service->phy_flow_on = false;
52b482cd20SSjur Braendeland 		break;
53b482cd20SSjur Braendeland 	case _CAIF_CTRLCMD_PHYIF_FLOW_ON_IND:
54b482cd20SSjur Braendeland 		if (phyid != service->dev_info.id)
55b482cd20SSjur Braendeland 			return;
56b482cd20SSjur Braendeland 		if (service->modem_flow_on) {
57b482cd20SSjur Braendeland 			layr->up->ctrlcmd(layr->up,
58b482cd20SSjur Braendeland 					   CAIF_CTRLCMD_FLOW_ON_IND,
59b482cd20SSjur Braendeland 					   phyid);
60b482cd20SSjur Braendeland 		}
61b482cd20SSjur Braendeland 		service->phy_flow_on = true;
62b482cd20SSjur Braendeland 		break;
63b482cd20SSjur Braendeland 	case CAIF_CTRLCMD_FLOW_OFF_IND:
64b482cd20SSjur Braendeland 		if (service->phy_flow_on) {
65b482cd20SSjur Braendeland 			layr->up->ctrlcmd(layr->up,
66b482cd20SSjur Braendeland 					  CAIF_CTRLCMD_FLOW_OFF_IND, phyid);
67b482cd20SSjur Braendeland 		}
68b482cd20SSjur Braendeland 		service->modem_flow_on = false;
69b482cd20SSjur Braendeland 		break;
70b482cd20SSjur Braendeland 	case CAIF_CTRLCMD_FLOW_ON_IND:
71b482cd20SSjur Braendeland 		if (service->phy_flow_on) {
72b482cd20SSjur Braendeland 			layr->up->ctrlcmd(layr->up,
73b482cd20SSjur Braendeland 					  CAIF_CTRLCMD_FLOW_ON_IND, phyid);
74b482cd20SSjur Braendeland 		}
75b482cd20SSjur Braendeland 		service->modem_flow_on = true;
76b482cd20SSjur Braendeland 		break;
77b482cd20SSjur Braendeland 	case _CAIF_CTRLCMD_PHYIF_DOWN_IND:
78b482cd20SSjur Braendeland 		/* In case interface is down, let's fake a remove shutdown */
79b482cd20SSjur Braendeland 		layr->up->ctrlcmd(layr->up,
80b482cd20SSjur Braendeland 				CAIF_CTRLCMD_REMOTE_SHUTDOWN_IND, phyid);
81b482cd20SSjur Braendeland 		break;
82b482cd20SSjur Braendeland 	case CAIF_CTRLCMD_REMOTE_SHUTDOWN_IND:
83b482cd20SSjur Braendeland 		layr->up->ctrlcmd(layr->up, ctrl, phyid);
84b482cd20SSjur Braendeland 		break;
85b482cd20SSjur Braendeland 	default:
86b31fa5baSJoe Perches 		pr_warn("Unexpected ctrl in cfsrvl (%d)\n", ctrl);
87b482cd20SSjur Braendeland 		/* We have both modem and phy flow on, send flow on */
88b482cd20SSjur Braendeland 		layr->up->ctrlcmd(layr->up, ctrl, phyid);
89b482cd20SSjur Braendeland 		service->phy_flow_on = true;
90b482cd20SSjur Braendeland 		break;
91b482cd20SSjur Braendeland 	}
92b482cd20SSjur Braendeland }
93b482cd20SSjur Braendeland 
cfservl_modemcmd(struct cflayer * layr,enum caif_modemcmd ctrl)94b482cd20SSjur Braendeland static int cfservl_modemcmd(struct cflayer *layr, enum caif_modemcmd ctrl)
95b482cd20SSjur Braendeland {
96b482cd20SSjur Braendeland 	struct cfsrvl *service = container_obj(layr);
97b1c74247SSjur Braendeland 
98b482cd20SSjur Braendeland 	caif_assert(layr != NULL);
99b482cd20SSjur Braendeland 	caif_assert(layr->dn != NULL);
100b482cd20SSjur Braendeland 	caif_assert(layr->dn->transmit != NULL);
101b1c74247SSjur Braendeland 
102b1c74247SSjur Braendeland 	if (!service->supports_flowctrl)
103b1c74247SSjur Braendeland 		return 0;
104b1c74247SSjur Braendeland 
105b482cd20SSjur Braendeland 	switch (ctrl) {
106b482cd20SSjur Braendeland 	case CAIF_MODEMCMD_FLOW_ON_REQ:
107b482cd20SSjur Braendeland 		{
108b482cd20SSjur Braendeland 			struct cfpkt *pkt;
109b482cd20SSjur Braendeland 			struct caif_payload_info *info;
110b482cd20SSjur Braendeland 			u8 flow_on = SRVL_FLOW_ON;
111b482cd20SSjur Braendeland 			pkt = cfpkt_create(SRVL_CTRL_PKT_SIZE);
1127ac2ed0cSJoe Perches 			if (!pkt)
113b482cd20SSjur Braendeland 				return -ENOMEM;
114b482cd20SSjur Braendeland 
115b482cd20SSjur Braendeland 			if (cfpkt_add_head(pkt, &flow_on, 1) < 0) {
116b31fa5baSJoe Perches 				pr_err("Packet is erroneous!\n");
117b482cd20SSjur Braendeland 				cfpkt_destroy(pkt);
118b482cd20SSjur Braendeland 				return -EPROTO;
119b482cd20SSjur Braendeland 			}
120b482cd20SSjur Braendeland 			info = cfpkt_info(pkt);
121b482cd20SSjur Braendeland 			info->channel_id = service->layer.id;
122b482cd20SSjur Braendeland 			info->hdr_len = 1;
123b482cd20SSjur Braendeland 			info->dev_info = &service->dev_info;
12444764812SDmitry Tarnyagin 			cfpkt_set_prio(pkt, TC_PRIO_CONTROL);
125b482cd20SSjur Braendeland 			return layr->dn->transmit(layr->dn, pkt);
126b482cd20SSjur Braendeland 		}
127b482cd20SSjur Braendeland 	case CAIF_MODEMCMD_FLOW_OFF_REQ:
128b482cd20SSjur Braendeland 		{
129b482cd20SSjur Braendeland 			struct cfpkt *pkt;
130b482cd20SSjur Braendeland 			struct caif_payload_info *info;
131b482cd20SSjur Braendeland 			u8 flow_off = SRVL_FLOW_OFF;
132b482cd20SSjur Braendeland 			pkt = cfpkt_create(SRVL_CTRL_PKT_SIZE);
1337ac2ed0cSJoe Perches 			if (!pkt)
134638e628aSSjur Braendeland 				return -ENOMEM;
135638e628aSSjur Braendeland 
136b482cd20SSjur Braendeland 			if (cfpkt_add_head(pkt, &flow_off, 1) < 0) {
137b31fa5baSJoe Perches 				pr_err("Packet is erroneous!\n");
138b482cd20SSjur Braendeland 				cfpkt_destroy(pkt);
139b482cd20SSjur Braendeland 				return -EPROTO;
140b482cd20SSjur Braendeland 			}
141b482cd20SSjur Braendeland 			info = cfpkt_info(pkt);
142b482cd20SSjur Braendeland 			info->channel_id = service->layer.id;
143b482cd20SSjur Braendeland 			info->hdr_len = 1;
144b482cd20SSjur Braendeland 			info->dev_info = &service->dev_info;
14544764812SDmitry Tarnyagin 			cfpkt_set_prio(pkt, TC_PRIO_CONTROL);
146b482cd20SSjur Braendeland 			return layr->dn->transmit(layr->dn, pkt);
147b482cd20SSjur Braendeland 		}
148b482cd20SSjur Braendeland 	default:
149b482cd20SSjur Braendeland 	  break;
150b482cd20SSjur Braendeland 	}
151b482cd20SSjur Braendeland 	return -EINVAL;
152b482cd20SSjur Braendeland }
153b482cd20SSjur Braendeland 
cfsrvl_release(struct cflayer * layer)15443e36921Ssjur.brandeland@stericsson.com static void cfsrvl_release(struct cflayer *layer)
155a7da1f55SSjur Braendeland {
15643e36921Ssjur.brandeland@stericsson.com 	struct cfsrvl *service = container_of(layer, struct cfsrvl, layer);
157a7da1f55SSjur Braendeland 	kfree(service);
158a7da1f55SSjur Braendeland }
159a7da1f55SSjur Braendeland 
cfsrvl_init(struct cfsrvl * service,u8 channel_id,struct dev_info * dev_info,bool supports_flowctrl)160b482cd20SSjur Braendeland void cfsrvl_init(struct cfsrvl *service,
161b482cd20SSjur Braendeland 		 u8 channel_id,
162b1c74247SSjur Braendeland 		 struct dev_info *dev_info,
1633bffc475SSilviu-Mihai Popescu 		 bool supports_flowctrl)
164b482cd20SSjur Braendeland {
165b482cd20SSjur Braendeland 	caif_assert(offsetof(struct cfsrvl, layer) == 0);
166b482cd20SSjur Braendeland 	service->open = false;
167b482cd20SSjur Braendeland 	service->modem_flow_on = true;
168b482cd20SSjur Braendeland 	service->phy_flow_on = true;
169b482cd20SSjur Braendeland 	service->layer.id = channel_id;
170b482cd20SSjur Braendeland 	service->layer.ctrlcmd = cfservl_ctrlcmd;
171b482cd20SSjur Braendeland 	service->layer.modemcmd = cfservl_modemcmd;
172b482cd20SSjur Braendeland 	service->dev_info = *dev_info;
173b1c74247SSjur Braendeland 	service->supports_flowctrl = supports_flowctrl;
174a7da1f55SSjur Braendeland 	service->release = cfsrvl_release;
1755b208656SSjur Braendeland }
1765b208656SSjur Braendeland 
cfsrvl_ready(struct cfsrvl * service,int * err)177b482cd20SSjur Braendeland bool cfsrvl_ready(struct cfsrvl *service, int *err)
178b482cd20SSjur Braendeland {
179b482cd20SSjur Braendeland 	if (!service->open) {
180b482cd20SSjur Braendeland 		*err = -ENOTCONN;
181b482cd20SSjur Braendeland 		return false;
182b482cd20SSjur Braendeland 	}
183374458b3SDmitry Tarnyagin 	return true;
184b482cd20SSjur Braendeland }
18543e36921Ssjur.brandeland@stericsson.com 
cfsrvl_getphyid(struct cflayer * layer)186b482cd20SSjur Braendeland u8 cfsrvl_getphyid(struct cflayer *layer)
187b482cd20SSjur Braendeland {
188b482cd20SSjur Braendeland 	struct cfsrvl *servl = container_obj(layer);
189b482cd20SSjur Braendeland 	return servl->dev_info.id;
190b482cd20SSjur Braendeland }
191b482cd20SSjur Braendeland 
cfsrvl_phyid_match(struct cflayer * layer,int phyid)192b482cd20SSjur Braendeland bool cfsrvl_phyid_match(struct cflayer *layer, int phyid)
193b482cd20SSjur Braendeland {
194b482cd20SSjur Braendeland 	struct cfsrvl *servl = container_obj(layer);
195b482cd20SSjur Braendeland 	return servl->dev_info.id == phyid;
196b482cd20SSjur Braendeland }
19743e36921Ssjur.brandeland@stericsson.com 
caif_free_client(struct cflayer * adap_layer)19843e36921Ssjur.brandeland@stericsson.com void caif_free_client(struct cflayer *adap_layer)
19943e36921Ssjur.brandeland@stericsson.com {
20043e36921Ssjur.brandeland@stericsson.com 	struct cfsrvl *servl;
20143e36921Ssjur.brandeland@stericsson.com 	if (adap_layer == NULL || adap_layer->dn == NULL)
20243e36921Ssjur.brandeland@stericsson.com 		return;
20343e36921Ssjur.brandeland@stericsson.com 	servl = container_obj(adap_layer->dn);
20443e36921Ssjur.brandeland@stericsson.com 	servl->release(&servl->layer);
20543e36921Ssjur.brandeland@stericsson.com }
20643e36921Ssjur.brandeland@stericsson.com EXPORT_SYMBOL(caif_free_client);
20743e36921Ssjur.brandeland@stericsson.com 
caif_client_register_refcnt(struct cflayer * adapt_layer,void (* hold)(struct cflayer * lyr),void (* put)(struct cflayer * lyr))20843e36921Ssjur.brandeland@stericsson.com void caif_client_register_refcnt(struct cflayer *adapt_layer,
20943e36921Ssjur.brandeland@stericsson.com 				 void (*hold)(struct cflayer *lyr),
21043e36921Ssjur.brandeland@stericsson.com 				 void (*put)(struct cflayer *lyr))
21143e36921Ssjur.brandeland@stericsson.com {
21243e36921Ssjur.brandeland@stericsson.com 	struct cfsrvl *service;
21343e36921Ssjur.brandeland@stericsson.com 
214566f26aaSWei Yongjun 	if (WARN_ON(adapt_layer == NULL || adapt_layer->dn == NULL))
215566f26aaSWei Yongjun 		return;
216566f26aaSWei Yongjun 	service = container_of(adapt_layer->dn, struct cfsrvl, layer);
21743e36921Ssjur.brandeland@stericsson.com 	service->hold = hold;
21843e36921Ssjur.brandeland@stericsson.com 	service->put = put;
21943e36921Ssjur.brandeland@stericsson.com }
22043e36921Ssjur.brandeland@stericsson.com EXPORT_SYMBOL(caif_client_register_refcnt);
221