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