File Index
Files and directories
Sign in
FILE

t7xx_port_proxy.c

File preview with syntax highlighting.

linux-6.19.14/drivers/net/wwan/t7xx/t7xx_port_proxy.c 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_MIPC		2
 42#define Q_IDX_ADB			3
 43#define Q_IDX_AT_CMD			5
 44
 45#define INVALID_SEQ_NUM			GENMASK(15, 0)
 46
 47#define for_each_proxy_port(i, p, proxy)	\
 48	for (i = 0, (p) = &(proxy)->ports[i];	\
 49	     i < (proxy)->port_count;		\
 50	     i++, (p) = &(proxy)->ports[i])
 51
 52#define T7XX_MAX_POSSIBLE_PORTS_NUM	\
 53	(max(ARRAY_SIZE(t7xx_port_conf), ARRAY_SIZE(t7xx_early_port_conf)))
 54
 55static const struct t7xx_port_conf t7xx_port_conf[] = {
 56	{
 57		.tx_ch = PORT_CH_UART2_TX,
 58		.rx_ch = PORT_CH_UART2_RX,
 59		.txq_index = Q_IDX_AT_CMD,
 60		.rxq_index = Q_IDX_AT_CMD,
 61		.txq_exp_index = 0xff,
 62		.rxq_exp_index = 0xff,
 63		.path_id = CLDMA_ID_MD,
 64		.ops = &wwan_sub_port_ops,
 65		.name = "AT",
 66		.port_type = WWAN_PORT_AT,
 67	}, {
 68		.tx_ch = PORT_CH_MBIM_TX,
 69		.rx_ch = PORT_CH_MBIM_RX,
 70		.txq_index = Q_IDX_MBIM_MIPC,
 71		.rxq_index = Q_IDX_MBIM_MIPC,
 72		.path_id = CLDMA_ID_MD,
 73		.ops = &wwan_sub_port_ops,
 74		.name = "MBIM",
 75		.port_type = WWAN_PORT_MBIM,
 76	}, {
 77#ifdef CONFIG_WWAN_DEBUGFS
 78		.tx_ch = PORT_CH_MD_LOG_TX,
 79		.rx_ch = PORT_CH_MD_LOG_RX,
 80		.txq_index = 7,
 81		.rxq_index = 7,
 82		.txq_exp_index = 7,
 83		.rxq_exp_index = 7,
 84		.path_id = CLDMA_ID_MD,
 85		.ops = &t7xx_trace_port_ops,
 86		.name = "mdlog",
 87	}, {
 88#endif
 89		.tx_ch = PORT_CH_CONTROL_TX,
 90		.rx_ch = PORT_CH_CONTROL_RX,
 91		.txq_index = Q_IDX_CTRL,
 92		.rxq_index = Q_IDX_CTRL,
 93		.path_id = CLDMA_ID_MD,
 94		.ops = &ctl_port_ops,
 95		.name = "t7xx_ctrl",
 96	}, {
 97		.tx_ch = PORT_CH_AP_CONTROL_TX,
 98		.rx_ch = PORT_CH_AP_CONTROL_RX,
 99		.txq_index = Q_IDX_CTRL,
100		.rxq_index = Q_IDX_CTRL,
101		.path_id = CLDMA_ID_AP,
102		.ops = &ctl_port_ops,
103		.name = "t7xx_ap_ctrl",
104	}, {
105		.tx_ch = PORT_CH_AP_ADB_TX,
106		.rx_ch = PORT_CH_AP_ADB_RX,
107		.txq_index = Q_IDX_ADB,
108		.rxq_index = Q_IDX_ADB,
109		.path_id = CLDMA_ID_AP,
110		.ops = &wwan_sub_port_ops,
111		.name = "adb",
112		.port_type = WWAN_PORT_ADB,
113		.debug = true,
114	}, {
115		.tx_ch = PORT_CH_MIPC_TX,
116		.rx_ch = PORT_CH_MIPC_RX,
117		.txq_index = Q_IDX_MBIM_MIPC,
118		.rxq_index = Q_IDX_MBIM_MIPC,
119		.path_id = CLDMA_ID_MD,
120		.ops = &wwan_sub_port_ops,
121		.name = "mipc",
122		.port_type = WWAN_PORT_MIPC,
123		.debug = true,
124	}
125};
126
127static const struct t7xx_port_conf t7xx_early_port_conf[] = {
128	{
129		.tx_ch = PORT_CH_UNIMPORTANT,
130		.rx_ch = PORT_CH_UNIMPORTANT,
131		.txq_index = CLDMA_Q_IDX_DUMP,
132		.rxq_index = CLDMA_Q_IDX_DUMP,
133		.txq_exp_index = CLDMA_Q_IDX_DUMP,
134		.rxq_exp_index = CLDMA_Q_IDX_DUMP,
135		.path_id = CLDMA_ID_AP,
136		.ops = &wwan_sub_port_ops,
137		.name = "fastboot",
138		.port_type = WWAN_PORT_FASTBOOT,
139	},
140};
141
142static struct t7xx_port *t7xx_proxy_get_port_by_ch(struct port_proxy *port_prox, enum port_ch ch)
143{
144	const struct t7xx_port_conf *port_conf;
145	struct t7xx_port *port;
146	int i;
147
148	for_each_proxy_port(i, port, port_prox) {
149		port_conf = port->port_conf;
150		if (port_conf->rx_ch == ch || port_conf->tx_ch == ch)
151			return port;
152	}
153
154	return NULL;
155}
156
157static u16 t7xx_port_next_rx_seq_num(struct t7xx_port *port, struct ccci_header *ccci_h)
158{
159	u32 status = le32_to_cpu(ccci_h->status);
160	u16 seq_num, next_seq_num;
161	bool assert_bit;
162
163	seq_num = FIELD_GET(CCCI_H_SEQ_FLD, status);
164	next_seq_num = (seq_num + 1) & FIELD_MAX(CCCI_H_SEQ_FLD);
165	assert_bit = status & CCCI_H_AST_BIT;
166	if (!assert_bit || port->seq_nums[MTK_RX] == INVALID_SEQ_NUM)
167		return next_seq_num;
168
169	if (seq_num != port->seq_nums[MTK_RX])
170		dev_warn_ratelimited(port->dev,
171				     "seq num out-of-order %u != %u (header %X, len %X)\n",
172				     seq_num, port->seq_nums[MTK_RX],
173				     le32_to_cpu(ccci_h->packet_header),
174				     le32_to_cpu(ccci_h->packet_len));
175
176	return next_seq_num;
177}
178
179void t7xx_port_proxy_reset(struct port_proxy *port_prox)
180{
181	struct t7xx_port *port;
182	int i;
183
184	for_each_proxy_port(i, port, port_prox) {
185		port->seq_nums[MTK_RX] = INVALID_SEQ_NUM;
186		port->seq_nums[MTK_TX] = 0;
187	}
188}
189
190static int t7xx_port_get_queue_no(struct t7xx_port *port)
191{
192	const struct t7xx_port_conf *port_conf = port->port_conf;
193	struct t7xx_fsm_ctl *ctl = port->t7xx_dev->md->fsm_ctl;
194
195	return t7xx_fsm_get_md_state(ctl) == MD_STATE_EXCEPTION ?
196		port_conf->txq_exp_index : port_conf->txq_index;
197}
198
199static void t7xx_port_struct_init(struct t7xx_port *port)
200{
201	INIT_LIST_HEAD(&port->entry);
202	INIT_LIST_HEAD(&port->queue_entry);
203	skb_queue_head_init(&port->rx_skb_list);
204	init_waitqueue_head(&port->rx_wq);
205	port->seq_nums[MTK_RX] = INVALID_SEQ_NUM;
206	port->seq_nums[MTK_TX] = 0;
207	atomic_set(&port->usage_cnt, 0);
208}
209
210struct sk_buff *t7xx_port_alloc_skb(int payload)
211{
212	struct sk_buff *skb = __dev_alloc_skb(payload + sizeof(struct ccci_header), GFP_KERNEL);
213
214	if (skb)
215		skb_reserve(skb, sizeof(struct ccci_header));
216
217	return skb;
218}
219
220struct sk_buff *t7xx_ctrl_alloc_skb(int payload)
221{
222	struct sk_buff *skb = t7xx_port_alloc_skb(payload + sizeof(struct ctrl_msg_header));
223
224	if (skb)
225		skb_reserve(skb, sizeof(struct ctrl_msg_header));
226
227	return skb;
228}
229
230/**
231 * t7xx_port_enqueue_skb() - Enqueue the received skb into the port's rx_skb_list.
232 * @port: port context.
233 * @skb: received skb.
234 *
235 * Return:
236 * * 0		- Success.
237 * * -ENOBUFS	- Not enough buffer space. Caller will try again later, skb is not consumed.
238 */
239int t7xx_port_enqueue_skb(struct t7xx_port *port, struct sk_buff *skb)
240{
241	unsigned long flags;
242
243	spin_lock_irqsave(&port->rx_wq.lock, flags);
244	if (port->rx_skb_list.qlen >= port->rx_length_th) {
245		spin_unlock_irqrestore(&port->rx_wq.lock, flags);
246
247		return -ENOBUFS;
248	}
249	__skb_queue_tail(&port->rx_skb_list, skb);
250	spin_unlock_irqrestore(&port->rx_wq.lock, flags);
251
252	wake_up_all(&port->rx_wq);
253	return 0;
254}
255
256int t7xx_get_port_mtu(struct t7xx_port *port)
257{
258	enum cldma_id path_id = port->port_conf->path_id;
259	int tx_qno = t7xx_port_get_queue_no(port);
260	struct cldma_ctrl *md_ctrl;
261
262	md_ctrl = port->t7xx_dev->md->md_ctrl[path_id];
263	return md_ctrl->tx_ring[tx_qno].pkt_size;
264}
265
266int t7xx_port_send_raw_skb(struct t7xx_port *port, struct sk_buff *skb)
267{
268	enum cldma_id path_id = port->port_conf->path_id;
269	struct cldma_ctrl *md_ctrl;
270	int ret, tx_qno;
271
272	md_ctrl = port->t7xx_dev->md->md_ctrl[path_id];
273	tx_qno = t7xx_port_get_queue_no(port);
274	ret = t7xx_cldma_send_skb(md_ctrl, tx_qno, skb);
275	if (ret)
276		dev_err(port->dev, "Failed to send skb: %d\n", ret);
277
278	return ret;
279}
280
281static int t7xx_port_send_ccci_skb(struct t7xx_port *port, struct sk_buff *skb,
282				   unsigned int pkt_header, unsigned int ex_msg)
283{
284	const struct t7xx_port_conf *port_conf = port->port_conf;
285	struct ccci_header *ccci_h;
286	u32 status;
287	int ret;
288
289	ccci_h = skb_push(skb, sizeof(*ccci_h));
290	status = FIELD_PREP(CCCI_H_CHN_FLD, port_conf->tx_ch) |
291		 FIELD_PREP(CCCI_H_SEQ_FLD, port->seq_nums[MTK_TX]) | CCCI_H_AST_BIT;
292	ccci_h->status = cpu_to_le32(status);
293	ccci_h->packet_header = cpu_to_le32(pkt_header);
294	ccci_h->packet_len = cpu_to_le32(skb->len);
295	ccci_h->ex_msg = cpu_to_le32(ex_msg);
296
297	ret = t7xx_port_send_raw_skb(port, skb);
298	if (ret)
299		return ret;
300
301	port->seq_nums[MTK_TX]++;
302	return 0;
303}
304
305int t7xx_port_send_ctl_skb(struct t7xx_port *port, struct sk_buff *skb, unsigned int msg,
306			   unsigned int ex_msg)
307{
308	struct ctrl_msg_header *ctrl_msg_h;
309	unsigned int msg_len = skb->len;
310	u32 pkt_header = 0;
311
312	ctrl_msg_h = skb_push(skb, sizeof(*ctrl_msg_h));
313	ctrl_msg_h->ctrl_msg_id = cpu_to_le32(msg);
314	ctrl_msg_h->ex_msg = cpu_to_le32(ex_msg);
315	ctrl_msg_h->data_length = cpu_to_le32(msg_len);
316
317	if (!msg_len)
318		pkt_header = CCCI_HEADER_NO_DATA;
319
320	return t7xx_port_send_ccci_skb(port, skb, pkt_header, ex_msg);
321}
322
323int t7xx_port_send_skb(struct t7xx_port *port, struct sk_buff *skb, unsigned int pkt_header,
324		       unsigned int ex_msg)
325{
326	struct t7xx_fsm_ctl *ctl = port->t7xx_dev->md->fsm_ctl;
327	unsigned int fsm_state;
328
329	fsm_state = t7xx_fsm_get_ctl_state(ctl);
330	if (fsm_state != FSM_STATE_PRE_START) {
331		const struct t7xx_port_conf *port_conf = port->port_conf;
332		enum md_state md_state = t7xx_fsm_get_md_state(ctl);
333
334		switch (md_state) {
335		case MD_STATE_EXCEPTION:
336			if (port_conf->tx_ch != PORT_CH_MD_LOG_TX)
337				return -EBUSY;
338			break;
339
340		case MD_STATE_WAITING_FOR_HS1:
341		case MD_STATE_WAITING_FOR_HS2:
342		case MD_STATE_STOPPED:
343		case MD_STATE_WAITING_TO_STOP:
344		case MD_STATE_INVALID:
345			return -ENODEV;
346
347		default:
348			break;
349		}
350	}
351
352	return t7xx_port_send_ccci_skb(port, skb, pkt_header, ex_msg);
353}
354
355static void t7xx_proxy_setup_ch_mapping(struct port_proxy *port_prox)
356{
357	struct t7xx_port *port;
358
359	int i, j;
360
361	for (i = 0; i < ARRAY_SIZE(port_prox->rx_ch_ports); i++)
362		INIT_LIST_HEAD(&port_prox->rx_ch_ports[i]);
363
364	for (j = 0; j < ARRAY_SIZE(port_prox->queue_ports); j++) {
365		for (i = 0; i < ARRAY_SIZE(port_prox->queue_ports[j]); i++)
366			INIT_LIST_HEAD(&port_prox->queue_ports[j][i]);
367	}
368
369	for_each_proxy_port(i, port, port_prox) {
370		const struct t7xx_port_conf *port_conf = port->port_conf;
371		enum cldma_id path_id = port_conf->path_id;
372		u8 ch_id;
373
374		ch_id = FIELD_GET(PORT_CH_ID_MASK, port_conf->rx_ch);
375		list_add_tail(&port->entry, &port_prox->rx_ch_ports[ch_id]);
376		list_add_tail(&port->queue_entry,
377			      &port_prox->queue_ports[path_id][port_conf->rxq_index]);
378	}
379}
380
381/**
382 * t7xx_port_proxy_recv_skb_from_dedicated_queue() - Dispatch early port received skb.
383 * @queue: CLDMA queue.
384 * @skb: Socket buffer.
385 *
386 * Return:
387 ** 0		- Packet consumed.
388 ** -ERROR	- Failed to process skb.
389 */
390int t7xx_port_proxy_recv_skb_from_dedicated_queue(struct cldma_queue *queue, struct sk_buff *skb)
391{
392	struct t7xx_pci_dev *t7xx_dev = queue->md_ctrl->t7xx_dev;
393	struct port_proxy *port_prox = t7xx_dev->md->port_prox;
394	const struct t7xx_port_conf *port_conf;
395	struct t7xx_port *port;
396	int ret;
397
398	port = &port_prox->ports[0];
399	if (WARN_ON_ONCE(port->port_conf->rxq_index != queue->index)) {
400		dev_kfree_skb_any(skb);
401		return -EINVAL;
402	}
403
404	port_conf = port->port_conf;
405	ret = port_conf->ops->recv_skb(port, skb);
406	if (ret < 0 && ret != -ENOBUFS) {
407		dev_err(port->dev, "drop on RX ch %d, %d\n", port_conf->rx_ch, ret);
408		dev_kfree_skb_any(skb);
409	}
410
411	return ret;
412}
413
414static struct t7xx_port *t7xx_port_proxy_find_port(struct t7xx_pci_dev *t7xx_dev,
415						   struct cldma_queue *queue, u16 channel)
416{
417	struct port_proxy *port_prox = t7xx_dev->md->port_prox;
418	struct list_head *port_list;
419	struct t7xx_port *port;
420	u8 ch_id;
421
422	ch_id = FIELD_GET(PORT_CH_ID_MASK, channel);
423	port_list = &port_prox->rx_ch_ports[ch_id];
424	list_for_each_entry(port, port_list, entry) {
425		const struct t7xx_port_conf *port_conf = port->port_conf;
426
427		if (queue->md_ctrl->hif_id == port_conf->path_id &&
428		    channel == port_conf->rx_ch)
429			return port;
430	}
431
432	return NULL;
433}
434
435/**
436 * t7xx_port_proxy_recv_skb() - Dispatch received skb.
437 * @queue: CLDMA queue.
438 * @skb: Socket buffer.
439 *
440 * Return:
441 ** 0		- Packet consumed.
442 ** -ERROR	- Failed to process skb.
443 */
444int t7xx_port_proxy_recv_skb(struct cldma_queue *queue, struct sk_buff *skb)
445{
446	struct ccci_header *ccci_h = (struct ccci_header *)skb->data;
447	struct t7xx_pci_dev *t7xx_dev = queue->md_ctrl->t7xx_dev;
448	struct t7xx_fsm_ctl *ctl = t7xx_dev->md->fsm_ctl;
449	struct device *dev = queue->md_ctrl->dev;
450	const struct t7xx_port_conf *port_conf;
451	struct t7xx_port *port;
452	u16 seq_num, channel;
453	int ret;
454
455	channel = FIELD_GET(CCCI_H_CHN_FLD, le32_to_cpu(ccci_h->status));
456	if (t7xx_fsm_get_md_state(ctl) == MD_STATE_INVALID) {
457		dev_err_ratelimited(dev, "Packet drop on channel 0x%x, modem not ready\n", channel);
458		goto drop_skb;
459	}
460
461	port = t7xx_port_proxy_find_port(t7xx_dev, queue, channel);
462	if (!port) {
463		dev_err_ratelimited(dev, "Packet drop on channel 0x%x, port not found\n", channel);
464		goto drop_skb;
465	}
466
467	seq_num = t7xx_port_next_rx_seq_num(port, ccci_h);
468	port_conf = port->port_conf;
469	skb_pull(skb, sizeof(*ccci_h));
470
471	ret = port_conf->ops->recv_skb(port, skb);
472	/* Error indicates to try again later */
473	if (ret) {
474		skb_push(skb, sizeof(*ccci_h));
475		return ret;
476	}
477
478	port->seq_nums[MTK_RX] = seq_num;
479	return 0;
480
481drop_skb:
482	dev_kfree_skb_any(skb);
483	return 0;
484}
485
486/**
487 * t7xx_port_proxy_md_status_notify() - Notify all ports of state.
488 *@port_prox: The port_proxy pointer.
489 *@state: State.
490 *
491 * Called by t7xx_fsm. Used to dispatch modem status for all ports,
492 * which want to know MD state transition.
493 */
494void t7xx_port_proxy_md_status_notify(struct port_proxy *port_prox, unsigned int state)
495{
496	struct t7xx_port *port;
497	int i;
498
499	for_each_proxy_port(i, port, port_prox) {
500		const struct t7xx_port_conf *port_conf = port->port_conf;
501
502		if (port_conf->ops->md_state_notify)
503			port_conf->ops->md_state_notify(port, state);
504	}
505}
506
507static void t7xx_proxy_init_all_ports(struct t7xx_modem *md)
508{
509	struct port_proxy *port_prox = md->port_prox;
510	struct t7xx_port *port;
511	int i;
512
513	for_each_proxy_port(i, port, port_prox) {
514		const struct t7xx_port_conf *port_conf = port->port_conf;
515
516		t7xx_port_struct_init(port);
517
518		if (port_conf->tx_ch == PORT_CH_CONTROL_TX)
519			md->core_md.ctl_port = port;
520
521		if (port_conf->tx_ch == PORT_CH_AP_CONTROL_TX)
522			md->core_ap.ctl_port = port;
523
524		port->t7xx_dev = md->t7xx_dev;
525		port->dev = &md->t7xx_dev->pdev->dev;
526		spin_lock_init(&port->port_update_lock);
527		port->chan_enable = false;
528
529		if (!port_conf->debug &&
530		    port_conf->ops &&
531		    port_conf->ops->init)
532			port_conf->ops->init(port);
533	}
534
535	t7xx_proxy_setup_ch_mapping(port_prox);
536}
537
538void t7xx_proxy_debug_ports_show(struct t7xx_pci_dev *t7xx_dev, bool show)
539{
540	struct port_proxy *port_prox = t7xx_dev->md->port_prox;
541	struct t7xx_port *port;
542	int i;
543
544	for_each_proxy_port(i, port, port_prox) {
545		const struct t7xx_port_conf *port_conf = port->port_conf;
546
547		if (port_conf->debug && port_conf->ops) {
548			if (show && port_conf->ops->init)
549				port_conf->ops->init(port);
550			else if (!show && port_conf->ops->uninit)
551				port_conf->ops->uninit(port);
552		}
553	}
554}
555
556void t7xx_port_proxy_set_cfg(struct t7xx_modem *md, enum port_cfg_id cfg_id)
557{
558	struct port_proxy *port_prox = md->port_prox;
559	const struct t7xx_port_conf *port_conf;
560	u32 port_count;
561	int i;
562
563	t7xx_port_proxy_uninit(port_prox);
564
565	if (cfg_id == PORT_CFG_ID_EARLY) {
566		port_conf = t7xx_early_port_conf;
567		port_count = ARRAY_SIZE(t7xx_early_port_conf);
568	} else {
569		port_conf = t7xx_port_conf;
570		port_count = ARRAY_SIZE(t7xx_port_conf);
571	}
572
573	for (i = 0; i < port_count; i++)
574		port_prox->ports[i].port_conf = &port_conf[i];
575
576	port_prox->cfg_id = cfg_id;
577	port_prox->port_count = port_count;
578
579	t7xx_proxy_init_all_ports(md);
580}
581
582static int t7xx_proxy_alloc(struct t7xx_modem *md)
583{
584	struct device *dev = &md->t7xx_dev->pdev->dev;
585	struct port_proxy *port_prox;
586
587	port_prox = devm_kzalloc(dev,
588				 struct_size(port_prox,
589					     ports,
590					     T7XX_MAX_POSSIBLE_PORTS_NUM),
591				 GFP_KERNEL);
592	if (!port_prox)
593		return -ENOMEM;
594
595	md->port_prox = port_prox;
596	port_prox->dev = dev;
597
598	return 0;
599}
600
601/**
602 * t7xx_port_proxy_init() - Initialize ports.
603 * @md: Modem.
604 *
605 * Create all port instances.
606 *
607 * Return:
608 * * 0		- Success.
609 * * -ERROR	- Error code from failure sub-initializations.
610 */
611int t7xx_port_proxy_init(struct t7xx_modem *md)
612{
613	int ret;
614
615	ret = t7xx_proxy_alloc(md);
616	if (ret)
617		return ret;
618
619	return 0;
620}
621
622void t7xx_port_proxy_uninit(struct port_proxy *port_prox)
623{
624	struct t7xx_port *port;
625	int i;
626
627	for_each_proxy_port(i, port, port_prox) {
628		const struct t7xx_port_conf *port_conf = port->port_conf;
629
630		if (port_conf->ops && port_conf->ops->uninit)
631			port_conf->ops->uninit(port);
632	}
633}
634
635int t7xx_port_proxy_chl_enable_disable(struct port_proxy *port_prox, unsigned int ch_id,
636				       bool en_flag)
637{
638	struct t7xx_port *port = t7xx_proxy_get_port_by_ch(port_prox, ch_id);
639	const struct t7xx_port_conf *port_conf;
640
641	if (!port)
642		return -EINVAL;
643
644	port_conf = port->port_conf;
645
646	if (en_flag) {
647		if (port_conf->ops->enable_chl)
648			port_conf->ops->enable_chl(port);
649	} else {
650		if (port_conf->ops->disable_chl)
651			port_conf->ops->disable_chl(port);
652	}
653
654	return 0;
655}
~/ Read-only file preview.