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
t7xx_port_wwan_start(struct wwan_port * port)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
t7xx_port_wwan_stop(struct wwan_port * port)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
t7xx_port_fastboot_tx(struct t7xx_port * port,struct sk_buff * skb)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
t7xx_port_ctrl_tx(struct t7xx_port * port,struct sk_buff * skb)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
t7xx_port_wwan_tx(struct wwan_port * port,struct sk_buff * skb)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
t7xx_port_wwan_create(struct t7xx_port * port)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
t7xx_port_wwan_init(struct t7xx_port * port)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 t7xx_port_wwan_create(port);
174
175 port->rx_length_th = RX_QUEUE_MAXLEN;
176 return 0;
177 }
178
t7xx_port_wwan_uninit(struct t7xx_port * port)179 static void t7xx_port_wwan_uninit(struct t7xx_port *port)
180 {
181 if (!port->wwan.wwan_port)
182 return;
183
184 port->rx_length_th = 0;
185 wwan_remove_port(port->wwan.wwan_port);
186 port->wwan.wwan_port = NULL;
187 }
188
t7xx_port_wwan_recv_skb(struct t7xx_port * port,struct sk_buff * skb)189 static int t7xx_port_wwan_recv_skb(struct t7xx_port *port, struct sk_buff *skb)
190 {
191 if (!atomic_read(&port->usage_cnt) || !port->chan_enable) {
192 const struct t7xx_port_conf *port_conf = port->port_conf;
193
194 dev_kfree_skb_any(skb);
195 dev_err_ratelimited(port->dev, "Port %s is not opened, drop packets\n",
196 port_conf->name);
197 /* Dropping skb, caller should not access skb.*/
198 return 0;
199 }
200
201 wwan_port_rx(port->wwan.wwan_port, skb);
202 return 0;
203 }
204
t7xx_port_wwan_enable_chl(struct t7xx_port * port)205 static int t7xx_port_wwan_enable_chl(struct t7xx_port *port)
206 {
207 spin_lock(&port->port_update_lock);
208 port->chan_enable = true;
209 spin_unlock(&port->port_update_lock);
210
211 return 0;
212 }
213
t7xx_port_wwan_disable_chl(struct t7xx_port * port)214 static int t7xx_port_wwan_disable_chl(struct t7xx_port *port)
215 {
216 spin_lock(&port->port_update_lock);
217 port->chan_enable = false;
218 spin_unlock(&port->port_update_lock);
219
220 return 0;
221 }
222
t7xx_port_wwan_md_state_notify(struct t7xx_port * port,unsigned int state)223 static void t7xx_port_wwan_md_state_notify(struct t7xx_port *port, unsigned int state)
224 {
225 const struct t7xx_port_conf *port_conf = port->port_conf;
226
227 if (port_conf->port_type == WWAN_PORT_FASTBOOT)
228 return;
229
230 if (state != MD_STATE_READY)
231 return;
232
233 t7xx_port_wwan_create(port);
234 }
235
236 struct port_ops wwan_sub_port_ops = {
237 .init = t7xx_port_wwan_init,
238 .recv_skb = t7xx_port_wwan_recv_skb,
239 .uninit = t7xx_port_wwan_uninit,
240 .enable_chl = t7xx_port_wwan_enable_chl,
241 .disable_chl = t7xx_port_wwan_disable_chl,
242 .md_state_notify = t7xx_port_wwan_md_state_notify,
243 };
244