xref: /linux/drivers/net/wwan/t7xx/t7xx_port_wwan.c (revision 7f71507851fc7764b36a3221839607d3a45c2025)
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * Copyright (c) 2021, MediaTek Inc.
4  * Copyright (c) 2021-2022, Intel Corporation.
5  * Copyright (c) 2024, Fibocom Wireless Inc.
6  *
7  * Authors:
8  *  Amir Hanania <amir.hanania@intel.com>
9  *  Chandrashekar Devegowda <chandrashekar.devegowda@intel.com>
10  *  Haijun Liu <haijun.liu@mediatek.com>
11  *  Moises Veleta <moises.veleta@intel.com>
12  *  Ricardo Martinez <ricardo.martinez@linux.intel.com>
13  *
14  * Contributors:
15  *  Andy Shevchenko <andriy.shevchenko@linux.intel.com>
16  *  Chiranjeevi Rapolu <chiranjeevi.rapolu@intel.com>
17  *  Eliot Lee <eliot.lee@intel.com>
18  *  Sreehari Kancharla <sreehari.kancharla@intel.com>
19  *  Jinjian Song <jinjian.song@fibocom.com>
20  */
21 
22 #include <linux/atomic.h>
23 #include <linux/bitfield.h>
24 #include <linux/dev_printk.h>
25 #include <linux/err.h>
26 #include <linux/gfp.h>
27 #include <linux/minmax.h>
28 #include <linux/netdevice.h>
29 #include <linux/skbuff.h>
30 #include <linux/spinlock.h>
31 #include <linux/string.h>
32 #include <linux/wwan.h>
33 
34 #include "t7xx_port.h"
35 #include "t7xx_port_proxy.h"
36 #include "t7xx_state_monitor.h"
37 
38 static int t7xx_port_wwan_start(struct wwan_port *port)
39 {
40 	struct t7xx_port *port_mtk = wwan_port_get_drvdata(port);
41 
42 	if (atomic_read(&port_mtk->usage_cnt))
43 		return -EBUSY;
44 
45 	atomic_inc(&port_mtk->usage_cnt);
46 	return 0;
47 }
48 
49 static void t7xx_port_wwan_stop(struct wwan_port *port)
50 {
51 	struct t7xx_port *port_mtk = wwan_port_get_drvdata(port);
52 
53 	atomic_dec(&port_mtk->usage_cnt);
54 }
55 
56 static int t7xx_port_fastboot_tx(struct t7xx_port *port, struct sk_buff *skb)
57 {
58 	struct sk_buff *cur = skb, *tx_skb;
59 	size_t actual, len, offset = 0;
60 	int txq_mtu;
61 	int ret;
62 
63 	txq_mtu = t7xx_get_port_mtu(port);
64 	if (txq_mtu < 0)
65 		return -EINVAL;
66 
67 	actual = cur->len;
68 	while (actual) {
69 		len = min_t(size_t, actual, txq_mtu);
70 		tx_skb = __dev_alloc_skb(len, GFP_KERNEL);
71 		if (!tx_skb)
72 			return -ENOMEM;
73 
74 		skb_put_data(tx_skb, cur->data + offset, len);
75 
76 		ret = t7xx_port_send_raw_skb(port, tx_skb);
77 		if (ret) {
78 			dev_kfree_skb(tx_skb);
79 			dev_err(port->dev, "Write error on fastboot port, %d\n", ret);
80 			break;
81 		}
82 		offset += len;
83 		actual -= len;
84 	}
85 
86 	dev_kfree_skb(skb);
87 	return 0;
88 }
89 
90 static int t7xx_port_ctrl_tx(struct t7xx_port *port, struct sk_buff *skb)
91 {
92 	const struct t7xx_port_conf *port_conf;
93 	struct sk_buff *cur = skb, *cloned;
94 	struct t7xx_fsm_ctl *ctl;
95 	enum md_state md_state;
96 	int cnt = 0, ret;
97 
98 	port_conf = port->port_conf;
99 	ctl = port->t7xx_dev->md->fsm_ctl;
100 	md_state = t7xx_fsm_get_md_state(ctl);
101 	if (md_state == MD_STATE_WAITING_FOR_HS1 || md_state == MD_STATE_WAITING_FOR_HS2) {
102 		dev_warn(port->dev, "Cannot write to %s port when md_state=%d\n",
103 			 port_conf->name, md_state);
104 		return -ENODEV;
105 	}
106 
107 	while (cur) {
108 		cloned = skb_clone(cur, GFP_KERNEL);
109 		cloned->len = skb_headlen(cur);
110 		ret = t7xx_port_send_skb(port, cloned, 0, 0);
111 		if (ret) {
112 			dev_kfree_skb(cloned);
113 			dev_err(port->dev, "Write error on %s port, %d\n",
114 				port_conf->name, ret);
115 			return cnt ? cnt + ret : ret;
116 		}
117 		cnt += cur->len;
118 		if (cur == skb)
119 			cur = skb_shinfo(skb)->frag_list;
120 		else
121 			cur = cur->next;
122 	}
123 
124 	dev_kfree_skb(skb);
125 	return 0;
126 }
127 
128 static int t7xx_port_wwan_tx(struct wwan_port *port, struct sk_buff *skb)
129 {
130 	struct t7xx_port *port_private = wwan_port_get_drvdata(port);
131 	const struct t7xx_port_conf *port_conf = port_private->port_conf;
132 	int ret;
133 
134 	if (!port_private->chan_enable)
135 		return -EINVAL;
136 
137 	if (port_conf->port_type != WWAN_PORT_FASTBOOT)
138 		ret = t7xx_port_ctrl_tx(port_private, skb);
139 	else
140 		ret = t7xx_port_fastboot_tx(port_private, skb);
141 
142 	return ret;
143 }
144 
145 static const struct wwan_port_ops wwan_ops = {
146 	.start = t7xx_port_wwan_start,
147 	.stop = t7xx_port_wwan_stop,
148 	.tx = t7xx_port_wwan_tx,
149 };
150 
151 static void t7xx_port_wwan_create(struct t7xx_port *port)
152 {
153 	const struct t7xx_port_conf *port_conf = port->port_conf;
154 	unsigned int header_len = sizeof(struct ccci_header), mtu;
155 	struct wwan_port_caps caps;
156 
157 	if (!port->wwan.wwan_port) {
158 		mtu = t7xx_get_port_mtu(port);
159 		caps.frag_len = mtu - header_len;
160 		caps.headroom_len = header_len;
161 		port->wwan.wwan_port = wwan_create_port(port->dev, port_conf->port_type,
162 							&wwan_ops, &caps, port);
163 		if (IS_ERR(port->wwan.wwan_port))
164 			dev_err(port->dev, "Unable to create WWAN port %s", port_conf->name);
165 	}
166 }
167 
168 static int t7xx_port_wwan_init(struct t7xx_port *port)
169 {
170 	const struct t7xx_port_conf *port_conf = port->port_conf;
171 
172 	if (port_conf->port_type == WWAN_PORT_FASTBOOT ||
173 	    port_conf->port_type == WWAN_PORT_ADB ||
174 	    port_conf->port_type == WWAN_PORT_MIPC)
175 		t7xx_port_wwan_create(port);
176 
177 	port->rx_length_th = RX_QUEUE_MAXLEN;
178 	return 0;
179 }
180 
181 static void t7xx_port_wwan_uninit(struct t7xx_port *port)
182 {
183 	if (!port->wwan.wwan_port)
184 		return;
185 
186 	port->rx_length_th = 0;
187 	wwan_remove_port(port->wwan.wwan_port);
188 	port->wwan.wwan_port = NULL;
189 }
190 
191 static int t7xx_port_wwan_recv_skb(struct t7xx_port *port, struct sk_buff *skb)
192 {
193 	if (!atomic_read(&port->usage_cnt) || !port->chan_enable) {
194 		const struct t7xx_port_conf *port_conf = port->port_conf;
195 
196 		dev_kfree_skb_any(skb);
197 		dev_err_ratelimited(port->dev, "Port %s is not opened, drop packets\n",
198 				    port_conf->name);
199 		/* Dropping skb, caller should not access skb.*/
200 		return 0;
201 	}
202 
203 	wwan_port_rx(port->wwan.wwan_port, skb);
204 	return 0;
205 }
206 
207 static int t7xx_port_wwan_enable_chl(struct t7xx_port *port)
208 {
209 	spin_lock(&port->port_update_lock);
210 	port->chan_enable = true;
211 	spin_unlock(&port->port_update_lock);
212 
213 	return 0;
214 }
215 
216 static int t7xx_port_wwan_disable_chl(struct t7xx_port *port)
217 {
218 	spin_lock(&port->port_update_lock);
219 	port->chan_enable = false;
220 	spin_unlock(&port->port_update_lock);
221 
222 	return 0;
223 }
224 
225 static void t7xx_port_wwan_md_state_notify(struct t7xx_port *port, unsigned int state)
226 {
227 	const struct t7xx_port_conf *port_conf = port->port_conf;
228 
229 	if (port_conf->port_type == WWAN_PORT_FASTBOOT ||
230 	    port_conf->port_type == WWAN_PORT_ADB ||
231 	    port_conf->port_type == WWAN_PORT_MIPC)
232 		return;
233 
234 	if (state != MD_STATE_READY)
235 		return;
236 
237 	t7xx_port_wwan_create(port);
238 }
239 
240 struct port_ops wwan_sub_port_ops = {
241 	.init = t7xx_port_wwan_init,
242 	.recv_skb = t7xx_port_wwan_recv_skb,
243 	.uninit = t7xx_port_wwan_uninit,
244 	.enable_chl = t7xx_port_wwan_enable_chl,
245 	.disable_chl = t7xx_port_wwan_disable_chl,
246 	.md_state_notify = t7xx_port_wwan_md_state_notify,
247 };
248