GNU Linux-libre 6.8.9-gnu
[releases.git] / drivers / net / wwan / t7xx / t7xx_port_proxy.c
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * Copyright (c) 2021, MediaTek Inc.
4  * Copyright (c) 2021-2022, Intel Corporation.
5  *
6  * Authors:
7  *  Amir Hanania <amir.hanania@intel.com>
8  *  Haijun Liu <haijun.liu@mediatek.com>
9  *  Moises Veleta <moises.veleta@intel.com>
10  *  Ricardo Martinez <ricardo.martinez@linux.intel.com>
11  *
12  * Contributors:
13  *  Andy Shevchenko <andriy.shevchenko@linux.intel.com>
14  *  Chandrashekar Devegowda <chandrashekar.devegowda@intel.com>
15  *  Chiranjeevi Rapolu <chiranjeevi.rapolu@intel.com>
16  *  Eliot Lee <eliot.lee@intel.com>
17  *  Sreehari Kancharla <sreehari.kancharla@intel.com>
18  */
19
20 #include <linux/bits.h>
21 #include <linux/bitfield.h>
22 #include <linux/device.h>
23 #include <linux/gfp.h>
24 #include <linux/kernel.h>
25 #include <linux/kthread.h>
26 #include <linux/list.h>
27 #include <linux/mutex.h>
28 #include <linux/netdevice.h>
29 #include <linux/skbuff.h>
30 #include <linux/spinlock.h>
31 #include <linux/wait.h>
32 #include <linux/wwan.h>
33
34 #include "t7xx_hif_cldma.h"
35 #include "t7xx_modem_ops.h"
36 #include "t7xx_port.h"
37 #include "t7xx_port_proxy.h"
38 #include "t7xx_state_monitor.h"
39
40 #define Q_IDX_CTRL                      0
41 #define Q_IDX_MBIM                      2
42 #define Q_IDX_AT_CMD                    5
43
44 #define INVALID_SEQ_NUM                 GENMASK(15, 0)
45
46 #define for_each_proxy_port(i, p, proxy)        \
47         for (i = 0, (p) = &(proxy)->ports[i];   \
48              i < (proxy)->port_count;           \
49              i++, (p) = &(proxy)->ports[i])
50
51 static const struct t7xx_port_conf t7xx_port_conf[] = {
52         {
53                 .tx_ch = PORT_CH_UART2_TX,
54                 .rx_ch = PORT_CH_UART2_RX,
55                 .txq_index = Q_IDX_AT_CMD,
56                 .rxq_index = Q_IDX_AT_CMD,
57                 .txq_exp_index = 0xff,
58                 .rxq_exp_index = 0xff,
59                 .path_id = CLDMA_ID_MD,
60                 .ops = &wwan_sub_port_ops,
61                 .name = "AT",
62                 .port_type = WWAN_PORT_AT,
63         }, {
64                 .tx_ch = PORT_CH_MBIM_TX,
65                 .rx_ch = PORT_CH_MBIM_RX,
66                 .txq_index = Q_IDX_MBIM,
67                 .rxq_index = Q_IDX_MBIM,
68                 .path_id = CLDMA_ID_MD,
69                 .ops = &wwan_sub_port_ops,
70                 .name = "MBIM",
71                 .port_type = WWAN_PORT_MBIM,
72         }, {
73 #ifdef CONFIG_WWAN_DEBUGFS
74                 .tx_ch = PORT_CH_MD_LOG_TX,
75                 .rx_ch = PORT_CH_MD_LOG_RX,
76                 .txq_index = 7,
77                 .rxq_index = 7,
78                 .txq_exp_index = 7,
79                 .rxq_exp_index = 7,
80                 .path_id = CLDMA_ID_MD,
81                 .ops = &t7xx_trace_port_ops,
82                 .name = "mdlog",
83         }, {
84 #endif
85                 .tx_ch = PORT_CH_CONTROL_TX,
86                 .rx_ch = PORT_CH_CONTROL_RX,
87                 .txq_index = Q_IDX_CTRL,
88                 .rxq_index = Q_IDX_CTRL,
89                 .path_id = CLDMA_ID_MD,
90                 .ops = &ctl_port_ops,
91                 .name = "t7xx_ctrl",
92         }, {
93                 .tx_ch = PORT_CH_AP_CONTROL_TX,
94                 .rx_ch = PORT_CH_AP_CONTROL_RX,
95                 .txq_index = Q_IDX_CTRL,
96                 .rxq_index = Q_IDX_CTRL,
97                 .path_id = CLDMA_ID_AP,
98                 .ops = &ctl_port_ops,
99                 .name = "t7xx_ap_ctrl",
100         },
101 };
102
103 static struct t7xx_port *t7xx_proxy_get_port_by_ch(struct port_proxy *port_prox, enum port_ch ch)
104 {
105         const struct t7xx_port_conf *port_conf;
106         struct t7xx_port *port;
107         int i;
108
109         for_each_proxy_port(i, port, port_prox) {
110                 port_conf = port->port_conf;
111                 if (port_conf->rx_ch == ch || port_conf->tx_ch == ch)
112                         return port;
113         }
114
115         return NULL;
116 }
117
118 static u16 t7xx_port_next_rx_seq_num(struct t7xx_port *port, struct ccci_header *ccci_h)
119 {
120         u32 status = le32_to_cpu(ccci_h->status);
121         u16 seq_num, next_seq_num;
122         bool assert_bit;
123
124         seq_num = FIELD_GET(CCCI_H_SEQ_FLD, status);
125         next_seq_num = (seq_num + 1) & FIELD_MAX(CCCI_H_SEQ_FLD);
126         assert_bit = status & CCCI_H_AST_BIT;
127         if (!assert_bit || port->seq_nums[MTK_RX] == INVALID_SEQ_NUM)
128                 return next_seq_num;
129
130         if (seq_num != port->seq_nums[MTK_RX])
131                 dev_warn_ratelimited(port->dev,
132                                      "seq num out-of-order %u != %u (header %X, len %X)\n",
133                                      seq_num, port->seq_nums[MTK_RX],
134                                      le32_to_cpu(ccci_h->packet_header),
135                                      le32_to_cpu(ccci_h->packet_len));
136
137         return next_seq_num;
138 }
139
140 void t7xx_port_proxy_reset(struct port_proxy *port_prox)
141 {
142         struct t7xx_port *port;
143         int i;
144
145         for_each_proxy_port(i, port, port_prox) {
146                 port->seq_nums[MTK_RX] = INVALID_SEQ_NUM;
147                 port->seq_nums[MTK_TX] = 0;
148         }
149 }
150
151 static int t7xx_port_get_queue_no(struct t7xx_port *port)
152 {
153         const struct t7xx_port_conf *port_conf = port->port_conf;
154         struct t7xx_fsm_ctl *ctl = port->t7xx_dev->md->fsm_ctl;
155
156         return t7xx_fsm_get_md_state(ctl) == MD_STATE_EXCEPTION ?
157                 port_conf->txq_exp_index : port_conf->txq_index;
158 }
159
160 static void t7xx_port_struct_init(struct t7xx_port *port)
161 {
162         INIT_LIST_HEAD(&port->entry);
163         INIT_LIST_HEAD(&port->queue_entry);
164         skb_queue_head_init(&port->rx_skb_list);
165         init_waitqueue_head(&port->rx_wq);
166         port->seq_nums[MTK_RX] = INVALID_SEQ_NUM;
167         port->seq_nums[MTK_TX] = 0;
168         atomic_set(&port->usage_cnt, 0);
169 }
170
171 struct sk_buff *t7xx_port_alloc_skb(int payload)
172 {
173         struct sk_buff *skb = __dev_alloc_skb(payload + sizeof(struct ccci_header), GFP_KERNEL);
174
175         if (skb)
176                 skb_reserve(skb, sizeof(struct ccci_header));
177
178         return skb;
179 }
180
181 struct sk_buff *t7xx_ctrl_alloc_skb(int payload)
182 {
183         struct sk_buff *skb = t7xx_port_alloc_skb(payload + sizeof(struct ctrl_msg_header));
184
185         if (skb)
186                 skb_reserve(skb, sizeof(struct ctrl_msg_header));
187
188         return skb;
189 }
190
191 /**
192  * t7xx_port_enqueue_skb() - Enqueue the received skb into the port's rx_skb_list.
193  * @port: port context.
194  * @skb: received skb.
195  *
196  * Return:
197  * * 0          - Success.
198  * * -ENOBUFS   - Not enough buffer space. Caller will try again later, skb is not consumed.
199  */
200 int t7xx_port_enqueue_skb(struct t7xx_port *port, struct sk_buff *skb)
201 {
202         unsigned long flags;
203
204         spin_lock_irqsave(&port->rx_wq.lock, flags);
205         if (port->rx_skb_list.qlen >= port->rx_length_th) {
206                 spin_unlock_irqrestore(&port->rx_wq.lock, flags);
207
208                 return -ENOBUFS;
209         }
210         __skb_queue_tail(&port->rx_skb_list, skb);
211         spin_unlock_irqrestore(&port->rx_wq.lock, flags);
212
213         wake_up_all(&port->rx_wq);
214         return 0;
215 }
216
217 static int t7xx_port_send_raw_skb(struct t7xx_port *port, struct sk_buff *skb)
218 {
219         enum cldma_id path_id = port->port_conf->path_id;
220         struct cldma_ctrl *md_ctrl;
221         int ret, tx_qno;
222
223         md_ctrl = port->t7xx_dev->md->md_ctrl[path_id];
224         tx_qno = t7xx_port_get_queue_no(port);
225         ret = t7xx_cldma_send_skb(md_ctrl, tx_qno, skb);
226         if (ret)
227                 dev_err(port->dev, "Failed to send skb: %d\n", ret);
228
229         return ret;
230 }
231
232 static int t7xx_port_send_ccci_skb(struct t7xx_port *port, struct sk_buff *skb,
233                                    unsigned int pkt_header, unsigned int ex_msg)
234 {
235         const struct t7xx_port_conf *port_conf = port->port_conf;
236         struct ccci_header *ccci_h;
237         u32 status;
238         int ret;
239
240         ccci_h = skb_push(skb, sizeof(*ccci_h));
241         status = FIELD_PREP(CCCI_H_CHN_FLD, port_conf->tx_ch) |
242                  FIELD_PREP(CCCI_H_SEQ_FLD, port->seq_nums[MTK_TX]) | CCCI_H_AST_BIT;
243         ccci_h->status = cpu_to_le32(status);
244         ccci_h->packet_header = cpu_to_le32(pkt_header);
245         ccci_h->packet_len = cpu_to_le32(skb->len);
246         ccci_h->ex_msg = cpu_to_le32(ex_msg);
247
248         ret = t7xx_port_send_raw_skb(port, skb);
249         if (ret)
250                 return ret;
251
252         port->seq_nums[MTK_TX]++;
253         return 0;
254 }
255
256 int t7xx_port_send_ctl_skb(struct t7xx_port *port, struct sk_buff *skb, unsigned int msg,
257                            unsigned int ex_msg)
258 {
259         struct ctrl_msg_header *ctrl_msg_h;
260         unsigned int msg_len = skb->len;
261         u32 pkt_header = 0;
262
263         ctrl_msg_h = skb_push(skb, sizeof(*ctrl_msg_h));
264         ctrl_msg_h->ctrl_msg_id = cpu_to_le32(msg);
265         ctrl_msg_h->ex_msg = cpu_to_le32(ex_msg);
266         ctrl_msg_h->data_length = cpu_to_le32(msg_len);
267
268         if (!msg_len)
269                 pkt_header = CCCI_HEADER_NO_DATA;
270
271         return t7xx_port_send_ccci_skb(port, skb, pkt_header, ex_msg);
272 }
273
274 int t7xx_port_send_skb(struct t7xx_port *port, struct sk_buff *skb, unsigned int pkt_header,
275                        unsigned int ex_msg)
276 {
277         struct t7xx_fsm_ctl *ctl = port->t7xx_dev->md->fsm_ctl;
278         unsigned int fsm_state;
279
280         fsm_state = t7xx_fsm_get_ctl_state(ctl);
281         if (fsm_state != FSM_STATE_PRE_START) {
282                 const struct t7xx_port_conf *port_conf = port->port_conf;
283                 enum md_state md_state = t7xx_fsm_get_md_state(ctl);
284
285                 switch (md_state) {
286                 case MD_STATE_EXCEPTION:
287                         if (port_conf->tx_ch != PORT_CH_MD_LOG_TX)
288                                 return -EBUSY;
289                         break;
290
291                 case MD_STATE_WAITING_FOR_HS1:
292                 case MD_STATE_WAITING_FOR_HS2:
293                 case MD_STATE_STOPPED:
294                 case MD_STATE_WAITING_TO_STOP:
295                 case MD_STATE_INVALID:
296                         return -ENODEV;
297
298                 default:
299                         break;
300                 }
301         }
302
303         return t7xx_port_send_ccci_skb(port, skb, pkt_header, ex_msg);
304 }
305
306 static void t7xx_proxy_setup_ch_mapping(struct port_proxy *port_prox)
307 {
308         struct t7xx_port *port;
309
310         int i, j;
311
312         for (i = 0; i < ARRAY_SIZE(port_prox->rx_ch_ports); i++)
313                 INIT_LIST_HEAD(&port_prox->rx_ch_ports[i]);
314
315         for (j = 0; j < ARRAY_SIZE(port_prox->queue_ports); j++) {
316                 for (i = 0; i < ARRAY_SIZE(port_prox->queue_ports[j]); i++)
317                         INIT_LIST_HEAD(&port_prox->queue_ports[j][i]);
318         }
319
320         for_each_proxy_port(i, port, port_prox) {
321                 const struct t7xx_port_conf *port_conf = port->port_conf;
322                 enum cldma_id path_id = port_conf->path_id;
323                 u8 ch_id;
324
325                 ch_id = FIELD_GET(PORT_CH_ID_MASK, port_conf->rx_ch);
326                 list_add_tail(&port->entry, &port_prox->rx_ch_ports[ch_id]);
327                 list_add_tail(&port->queue_entry,
328                               &port_prox->queue_ports[path_id][port_conf->rxq_index]);
329         }
330 }
331
332 static struct t7xx_port *t7xx_port_proxy_find_port(struct t7xx_pci_dev *t7xx_dev,
333                                                    struct cldma_queue *queue, u16 channel)
334 {
335         struct port_proxy *port_prox = t7xx_dev->md->port_prox;
336         struct list_head *port_list;
337         struct t7xx_port *port;
338         u8 ch_id;
339
340         ch_id = FIELD_GET(PORT_CH_ID_MASK, channel);
341         port_list = &port_prox->rx_ch_ports[ch_id];
342         list_for_each_entry(port, port_list, entry) {
343                 const struct t7xx_port_conf *port_conf = port->port_conf;
344
345                 if (queue->md_ctrl->hif_id == port_conf->path_id &&
346                     channel == port_conf->rx_ch)
347                         return port;
348         }
349
350         return NULL;
351 }
352
353 /**
354  * t7xx_port_proxy_recv_skb() - Dispatch received skb.
355  * @queue: CLDMA queue.
356  * @skb: Socket buffer.
357  *
358  * Return:
359  ** 0           - Packet consumed.
360  ** -ERROR      - Failed to process skb.
361  */
362 static int t7xx_port_proxy_recv_skb(struct cldma_queue *queue, struct sk_buff *skb)
363 {
364         struct ccci_header *ccci_h = (struct ccci_header *)skb->data;
365         struct t7xx_pci_dev *t7xx_dev = queue->md_ctrl->t7xx_dev;
366         struct t7xx_fsm_ctl *ctl = t7xx_dev->md->fsm_ctl;
367         struct device *dev = queue->md_ctrl->dev;
368         const struct t7xx_port_conf *port_conf;
369         struct t7xx_port *port;
370         u16 seq_num, channel;
371         int ret;
372
373         channel = FIELD_GET(CCCI_H_CHN_FLD, le32_to_cpu(ccci_h->status));
374         if (t7xx_fsm_get_md_state(ctl) == MD_STATE_INVALID) {
375                 dev_err_ratelimited(dev, "Packet drop on channel 0x%x, modem not ready\n", channel);
376                 goto drop_skb;
377         }
378
379         port = t7xx_port_proxy_find_port(t7xx_dev, queue, channel);
380         if (!port) {
381                 dev_err_ratelimited(dev, "Packet drop on channel 0x%x, port not found\n", channel);
382                 goto drop_skb;
383         }
384
385         seq_num = t7xx_port_next_rx_seq_num(port, ccci_h);
386         port_conf = port->port_conf;
387         skb_pull(skb, sizeof(*ccci_h));
388
389         ret = port_conf->ops->recv_skb(port, skb);
390         /* Error indicates to try again later */
391         if (ret) {
392                 skb_push(skb, sizeof(*ccci_h));
393                 return ret;
394         }
395
396         port->seq_nums[MTK_RX] = seq_num;
397         return 0;
398
399 drop_skb:
400         dev_kfree_skb_any(skb);
401         return 0;
402 }
403
404 /**
405  * t7xx_port_proxy_md_status_notify() - Notify all ports of state.
406  *@port_prox: The port_proxy pointer.
407  *@state: State.
408  *
409  * Called by t7xx_fsm. Used to dispatch modem status for all ports,
410  * which want to know MD state transition.
411  */
412 void t7xx_port_proxy_md_status_notify(struct port_proxy *port_prox, unsigned int state)
413 {
414         struct t7xx_port *port;
415         int i;
416
417         for_each_proxy_port(i, port, port_prox) {
418                 const struct t7xx_port_conf *port_conf = port->port_conf;
419
420                 if (port_conf->ops->md_state_notify)
421                         port_conf->ops->md_state_notify(port, state);
422         }
423 }
424
425 static void t7xx_proxy_init_all_ports(struct t7xx_modem *md)
426 {
427         struct port_proxy *port_prox = md->port_prox;
428         struct t7xx_port *port;
429         int i;
430
431         for_each_proxy_port(i, port, port_prox) {
432                 const struct t7xx_port_conf *port_conf = port->port_conf;
433
434                 t7xx_port_struct_init(port);
435
436                 if (port_conf->tx_ch == PORT_CH_CONTROL_TX)
437                         md->core_md.ctl_port = port;
438
439                 if (port_conf->tx_ch == PORT_CH_AP_CONTROL_TX)
440                         md->core_ap.ctl_port = port;
441
442                 port->t7xx_dev = md->t7xx_dev;
443                 port->dev = &md->t7xx_dev->pdev->dev;
444                 spin_lock_init(&port->port_update_lock);
445                 port->chan_enable = false;
446
447                 if (port_conf->ops->init)
448                         port_conf->ops->init(port);
449         }
450
451         t7xx_proxy_setup_ch_mapping(port_prox);
452 }
453
454 static int t7xx_proxy_alloc(struct t7xx_modem *md)
455 {
456         unsigned int port_count = ARRAY_SIZE(t7xx_port_conf);
457         struct device *dev = &md->t7xx_dev->pdev->dev;
458         struct port_proxy *port_prox;
459         int i;
460
461         port_prox = devm_kzalloc(dev, sizeof(*port_prox) + sizeof(struct t7xx_port) * port_count,
462                                  GFP_KERNEL);
463         if (!port_prox)
464                 return -ENOMEM;
465
466         md->port_prox = port_prox;
467         port_prox->dev = dev;
468
469         for (i = 0; i < port_count; i++)
470                 port_prox->ports[i].port_conf = &t7xx_port_conf[i];
471
472         port_prox->port_count = port_count;
473         t7xx_proxy_init_all_ports(md);
474         return 0;
475 }
476
477 /**
478  * t7xx_port_proxy_init() - Initialize ports.
479  * @md: Modem.
480  *
481  * Create all port instances.
482  *
483  * Return:
484  * * 0          - Success.
485  * * -ERROR     - Error code from failure sub-initializations.
486  */
487 int t7xx_port_proxy_init(struct t7xx_modem *md)
488 {
489         int ret;
490
491         ret = t7xx_proxy_alloc(md);
492         if (ret)
493                 return ret;
494
495         t7xx_cldma_set_recv_skb(md->md_ctrl[CLDMA_ID_AP], t7xx_port_proxy_recv_skb);
496         t7xx_cldma_set_recv_skb(md->md_ctrl[CLDMA_ID_MD], t7xx_port_proxy_recv_skb);
497         return 0;
498 }
499
500 void t7xx_port_proxy_uninit(struct port_proxy *port_prox)
501 {
502         struct t7xx_port *port;
503         int i;
504
505         for_each_proxy_port(i, port, port_prox) {
506                 const struct t7xx_port_conf *port_conf = port->port_conf;
507
508                 if (port_conf->ops->uninit)
509                         port_conf->ops->uninit(port);
510         }
511 }
512
513 int t7xx_port_proxy_chl_enable_disable(struct port_proxy *port_prox, unsigned int ch_id,
514                                        bool en_flag)
515 {
516         struct t7xx_port *port = t7xx_proxy_get_port_by_ch(port_prox, ch_id);
517         const struct t7xx_port_conf *port_conf;
518
519         if (!port)
520                 return -EINVAL;
521
522         port_conf = port->port_conf;
523
524         if (en_flag) {
525                 if (port_conf->ops->enable_chl)
526                         port_conf->ops->enable_chl(port);
527         } else {
528                 if (port_conf->ops->disable_chl)
529                         port_conf->ops->disable_chl(port);
530         }
531
532         return 0;
533 }