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 55 static 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 127 static 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 142 static 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 157 static 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 179 void 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 190 static 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 199 static 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 210 struct 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 220 struct 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 */ 239 int 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 256 int 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 266 int 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 281 static 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 305 int 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 323 int 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 355 static 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 */ 390 int 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 414 static 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 */ 444 int 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 481 drop_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 */ 494 void 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 507 static 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 538 void 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 556 void 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 582 static 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 */ 611 int 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 622 void 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 635 int 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 } 656