162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Copyright (c) 2021, MediaTek Inc.
462306a36Sopenharmony_ci * Copyright (c) 2021-2022, Intel Corporation.
562306a36Sopenharmony_ci *
662306a36Sopenharmony_ci * Authors:
762306a36Sopenharmony_ci *  Amir Hanania <amir.hanania@intel.com>
862306a36Sopenharmony_ci *  Haijun Liu <haijun.liu@mediatek.com>
962306a36Sopenharmony_ci *  Moises Veleta <moises.veleta@intel.com>
1062306a36Sopenharmony_ci *  Ricardo Martinez <ricardo.martinez@linux.intel.com>
1162306a36Sopenharmony_ci *
1262306a36Sopenharmony_ci * Contributors:
1362306a36Sopenharmony_ci *  Chiranjeevi Rapolu <chiranjeevi.rapolu@intel.com>
1462306a36Sopenharmony_ci *  Eliot Lee <eliot.lee@intel.com>
1562306a36Sopenharmony_ci *  Sreehari Kancharla <sreehari.kancharla@intel.com>
1662306a36Sopenharmony_ci */
1762306a36Sopenharmony_ci
1862306a36Sopenharmony_ci#include <linux/device.h>
1962306a36Sopenharmony_ci#include <linux/gfp.h>
2062306a36Sopenharmony_ci#include <linux/irqreturn.h>
2162306a36Sopenharmony_ci#include <linux/kernel.h>
2262306a36Sopenharmony_ci#include <linux/list.h>
2362306a36Sopenharmony_ci#include <linux/string.h>
2462306a36Sopenharmony_ci#include <linux/wait.h>
2562306a36Sopenharmony_ci#include <linux/workqueue.h>
2662306a36Sopenharmony_ci
2762306a36Sopenharmony_ci#include "t7xx_dpmaif.h"
2862306a36Sopenharmony_ci#include "t7xx_hif_dpmaif.h"
2962306a36Sopenharmony_ci#include "t7xx_hif_dpmaif_rx.h"
3062306a36Sopenharmony_ci#include "t7xx_hif_dpmaif_tx.h"
3162306a36Sopenharmony_ci#include "t7xx_pci.h"
3262306a36Sopenharmony_ci#include "t7xx_pcie_mac.h"
3362306a36Sopenharmony_ci#include "t7xx_state_monitor.h"
3462306a36Sopenharmony_ci
3562306a36Sopenharmony_ciunsigned int t7xx_ring_buf_get_next_wr_idx(unsigned int buf_len, unsigned int buf_idx)
3662306a36Sopenharmony_ci{
3762306a36Sopenharmony_ci	buf_idx++;
3862306a36Sopenharmony_ci
3962306a36Sopenharmony_ci	return buf_idx < buf_len ? buf_idx : 0;
4062306a36Sopenharmony_ci}
4162306a36Sopenharmony_ci
4262306a36Sopenharmony_ciunsigned int t7xx_ring_buf_rd_wr_count(unsigned int total_cnt, unsigned int rd_idx,
4362306a36Sopenharmony_ci				       unsigned int wr_idx, enum dpmaif_rdwr rd_wr)
4462306a36Sopenharmony_ci{
4562306a36Sopenharmony_ci	int pkt_cnt;
4662306a36Sopenharmony_ci
4762306a36Sopenharmony_ci	if (rd_wr == DPMAIF_READ)
4862306a36Sopenharmony_ci		pkt_cnt = wr_idx - rd_idx;
4962306a36Sopenharmony_ci	else
5062306a36Sopenharmony_ci		pkt_cnt = rd_idx - wr_idx - 1;
5162306a36Sopenharmony_ci
5262306a36Sopenharmony_ci	if (pkt_cnt < 0)
5362306a36Sopenharmony_ci		pkt_cnt += total_cnt;
5462306a36Sopenharmony_ci
5562306a36Sopenharmony_ci	return (unsigned int)pkt_cnt;
5662306a36Sopenharmony_ci}
5762306a36Sopenharmony_ci
5862306a36Sopenharmony_cistatic void t7xx_dpmaif_enable_irq(struct dpmaif_ctrl *dpmaif_ctrl)
5962306a36Sopenharmony_ci{
6062306a36Sopenharmony_ci	struct dpmaif_isr_para *isr_para;
6162306a36Sopenharmony_ci	int i;
6262306a36Sopenharmony_ci
6362306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(dpmaif_ctrl->isr_para); i++) {
6462306a36Sopenharmony_ci		isr_para = &dpmaif_ctrl->isr_para[i];
6562306a36Sopenharmony_ci		t7xx_pcie_mac_set_int(dpmaif_ctrl->t7xx_dev, isr_para->pcie_int);
6662306a36Sopenharmony_ci	}
6762306a36Sopenharmony_ci}
6862306a36Sopenharmony_ci
6962306a36Sopenharmony_cistatic void t7xx_dpmaif_disable_irq(struct dpmaif_ctrl *dpmaif_ctrl)
7062306a36Sopenharmony_ci{
7162306a36Sopenharmony_ci	struct dpmaif_isr_para *isr_para;
7262306a36Sopenharmony_ci	int i;
7362306a36Sopenharmony_ci
7462306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(dpmaif_ctrl->isr_para); i++) {
7562306a36Sopenharmony_ci		isr_para = &dpmaif_ctrl->isr_para[i];
7662306a36Sopenharmony_ci		t7xx_pcie_mac_clear_int(dpmaif_ctrl->t7xx_dev, isr_para->pcie_int);
7762306a36Sopenharmony_ci	}
7862306a36Sopenharmony_ci}
7962306a36Sopenharmony_ci
8062306a36Sopenharmony_cistatic void t7xx_dpmaif_irq_cb(struct dpmaif_isr_para *isr_para)
8162306a36Sopenharmony_ci{
8262306a36Sopenharmony_ci	struct dpmaif_ctrl *dpmaif_ctrl = isr_para->dpmaif_ctrl;
8362306a36Sopenharmony_ci	struct dpmaif_hw_intr_st_para intr_status;
8462306a36Sopenharmony_ci	struct device *dev = dpmaif_ctrl->dev;
8562306a36Sopenharmony_ci	struct dpmaif_hw_info *hw_info;
8662306a36Sopenharmony_ci	int i;
8762306a36Sopenharmony_ci
8862306a36Sopenharmony_ci	memset(&intr_status, 0, sizeof(intr_status));
8962306a36Sopenharmony_ci	hw_info = &dpmaif_ctrl->hw_info;
9062306a36Sopenharmony_ci
9162306a36Sopenharmony_ci	if (t7xx_dpmaif_hw_get_intr_cnt(hw_info, &intr_status, isr_para->dlq_id) < 0) {
9262306a36Sopenharmony_ci		dev_err(dev, "Failed to get HW interrupt count\n");
9362306a36Sopenharmony_ci		return;
9462306a36Sopenharmony_ci	}
9562306a36Sopenharmony_ci
9662306a36Sopenharmony_ci	t7xx_pcie_mac_clear_int_status(dpmaif_ctrl->t7xx_dev, isr_para->pcie_int);
9762306a36Sopenharmony_ci
9862306a36Sopenharmony_ci	for (i = 0; i < intr_status.intr_cnt; i++) {
9962306a36Sopenharmony_ci		switch (intr_status.intr_types[i]) {
10062306a36Sopenharmony_ci		case DPF_INTR_UL_DONE:
10162306a36Sopenharmony_ci			t7xx_dpmaif_irq_tx_done(dpmaif_ctrl, intr_status.intr_queues[i]);
10262306a36Sopenharmony_ci			break;
10362306a36Sopenharmony_ci
10462306a36Sopenharmony_ci		case DPF_INTR_UL_DRB_EMPTY:
10562306a36Sopenharmony_ci		case DPF_INTR_UL_MD_NOTREADY:
10662306a36Sopenharmony_ci		case DPF_INTR_UL_MD_PWR_NOTREADY:
10762306a36Sopenharmony_ci			/* No need to log an error for these */
10862306a36Sopenharmony_ci			break;
10962306a36Sopenharmony_ci
11062306a36Sopenharmony_ci		case DPF_INTR_DL_BATCNT_LEN_ERR:
11162306a36Sopenharmony_ci			dev_err_ratelimited(dev, "DL interrupt: packet BAT count length error\n");
11262306a36Sopenharmony_ci			t7xx_dpmaif_dl_unmask_batcnt_len_err_intr(hw_info);
11362306a36Sopenharmony_ci			break;
11462306a36Sopenharmony_ci
11562306a36Sopenharmony_ci		case DPF_INTR_DL_PITCNT_LEN_ERR:
11662306a36Sopenharmony_ci			dev_err_ratelimited(dev, "DL interrupt: PIT count length error\n");
11762306a36Sopenharmony_ci			t7xx_dpmaif_dl_unmask_pitcnt_len_err_intr(hw_info);
11862306a36Sopenharmony_ci			break;
11962306a36Sopenharmony_ci
12062306a36Sopenharmony_ci		case DPF_INTR_DL_Q0_PITCNT_LEN_ERR:
12162306a36Sopenharmony_ci			dev_err_ratelimited(dev, "DL interrupt: DLQ0 PIT count length error\n");
12262306a36Sopenharmony_ci			t7xx_dpmaif_dlq_unmask_pitcnt_len_err_intr(hw_info, DPF_RX_QNO_DFT);
12362306a36Sopenharmony_ci			break;
12462306a36Sopenharmony_ci
12562306a36Sopenharmony_ci		case DPF_INTR_DL_Q1_PITCNT_LEN_ERR:
12662306a36Sopenharmony_ci			dev_err_ratelimited(dev, "DL interrupt: DLQ1 PIT count length error\n");
12762306a36Sopenharmony_ci			t7xx_dpmaif_dlq_unmask_pitcnt_len_err_intr(hw_info, DPF_RX_QNO1);
12862306a36Sopenharmony_ci			break;
12962306a36Sopenharmony_ci
13062306a36Sopenharmony_ci		case DPF_INTR_DL_DONE:
13162306a36Sopenharmony_ci		case DPF_INTR_DL_Q0_DONE:
13262306a36Sopenharmony_ci		case DPF_INTR_DL_Q1_DONE:
13362306a36Sopenharmony_ci			t7xx_dpmaif_irq_rx_done(dpmaif_ctrl, intr_status.intr_queues[i]);
13462306a36Sopenharmony_ci			break;
13562306a36Sopenharmony_ci
13662306a36Sopenharmony_ci		default:
13762306a36Sopenharmony_ci			dev_err_ratelimited(dev, "DL interrupt error: unknown type : %d\n",
13862306a36Sopenharmony_ci					    intr_status.intr_types[i]);
13962306a36Sopenharmony_ci		}
14062306a36Sopenharmony_ci	}
14162306a36Sopenharmony_ci}
14262306a36Sopenharmony_ci
14362306a36Sopenharmony_cistatic irqreturn_t t7xx_dpmaif_isr_handler(int irq, void *data)
14462306a36Sopenharmony_ci{
14562306a36Sopenharmony_ci	struct dpmaif_isr_para *isr_para = data;
14662306a36Sopenharmony_ci	struct dpmaif_ctrl *dpmaif_ctrl;
14762306a36Sopenharmony_ci
14862306a36Sopenharmony_ci	dpmaif_ctrl = isr_para->dpmaif_ctrl;
14962306a36Sopenharmony_ci	if (dpmaif_ctrl->state != DPMAIF_STATE_PWRON) {
15062306a36Sopenharmony_ci		dev_err(dpmaif_ctrl->dev, "Interrupt received before initializing DPMAIF\n");
15162306a36Sopenharmony_ci		return IRQ_HANDLED;
15262306a36Sopenharmony_ci	}
15362306a36Sopenharmony_ci
15462306a36Sopenharmony_ci	t7xx_pcie_mac_clear_int(dpmaif_ctrl->t7xx_dev, isr_para->pcie_int);
15562306a36Sopenharmony_ci
15662306a36Sopenharmony_ci	return IRQ_WAKE_THREAD;
15762306a36Sopenharmony_ci}
15862306a36Sopenharmony_ci
15962306a36Sopenharmony_cistatic irqreturn_t t7xx_dpmaif_isr_thread(int irq, void *data)
16062306a36Sopenharmony_ci{
16162306a36Sopenharmony_ci	struct dpmaif_isr_para *isr_para = data;
16262306a36Sopenharmony_ci	struct dpmaif_ctrl *dpmaif_ctrl = isr_para->dpmaif_ctrl;
16362306a36Sopenharmony_ci
16462306a36Sopenharmony_ci	t7xx_dpmaif_irq_cb(isr_para);
16562306a36Sopenharmony_ci	t7xx_pcie_mac_set_int(dpmaif_ctrl->t7xx_dev, isr_para->pcie_int);
16662306a36Sopenharmony_ci	return IRQ_HANDLED;
16762306a36Sopenharmony_ci}
16862306a36Sopenharmony_ci
16962306a36Sopenharmony_cistatic void t7xx_dpmaif_isr_parameter_init(struct dpmaif_ctrl *dpmaif_ctrl)
17062306a36Sopenharmony_ci{
17162306a36Sopenharmony_ci	struct dpmaif_isr_para *isr_para;
17262306a36Sopenharmony_ci	unsigned char i;
17362306a36Sopenharmony_ci
17462306a36Sopenharmony_ci	dpmaif_ctrl->rxq_int_mapping[DPF_RX_QNO0] = DPMAIF_INT;
17562306a36Sopenharmony_ci	dpmaif_ctrl->rxq_int_mapping[DPF_RX_QNO1] = DPMAIF2_INT;
17662306a36Sopenharmony_ci
17762306a36Sopenharmony_ci	for (i = 0; i < DPMAIF_RXQ_NUM; i++) {
17862306a36Sopenharmony_ci		isr_para = &dpmaif_ctrl->isr_para[i];
17962306a36Sopenharmony_ci		isr_para->dpmaif_ctrl = dpmaif_ctrl;
18062306a36Sopenharmony_ci		isr_para->dlq_id = i;
18162306a36Sopenharmony_ci		isr_para->pcie_int = dpmaif_ctrl->rxq_int_mapping[i];
18262306a36Sopenharmony_ci	}
18362306a36Sopenharmony_ci}
18462306a36Sopenharmony_ci
18562306a36Sopenharmony_cistatic void t7xx_dpmaif_register_pcie_irq(struct dpmaif_ctrl *dpmaif_ctrl)
18662306a36Sopenharmony_ci{
18762306a36Sopenharmony_ci	struct t7xx_pci_dev *t7xx_dev = dpmaif_ctrl->t7xx_dev;
18862306a36Sopenharmony_ci	struct dpmaif_isr_para *isr_para;
18962306a36Sopenharmony_ci	enum t7xx_int int_type;
19062306a36Sopenharmony_ci	int i;
19162306a36Sopenharmony_ci
19262306a36Sopenharmony_ci	t7xx_dpmaif_isr_parameter_init(dpmaif_ctrl);
19362306a36Sopenharmony_ci
19462306a36Sopenharmony_ci	for (i = 0; i < DPMAIF_RXQ_NUM; i++) {
19562306a36Sopenharmony_ci		isr_para = &dpmaif_ctrl->isr_para[i];
19662306a36Sopenharmony_ci		int_type = isr_para->pcie_int;
19762306a36Sopenharmony_ci		t7xx_pcie_mac_clear_int(t7xx_dev, int_type);
19862306a36Sopenharmony_ci
19962306a36Sopenharmony_ci		t7xx_dev->intr_handler[int_type] = t7xx_dpmaif_isr_handler;
20062306a36Sopenharmony_ci		t7xx_dev->intr_thread[int_type] = t7xx_dpmaif_isr_thread;
20162306a36Sopenharmony_ci		t7xx_dev->callback_param[int_type] = isr_para;
20262306a36Sopenharmony_ci
20362306a36Sopenharmony_ci		t7xx_pcie_mac_clear_int_status(t7xx_dev, int_type);
20462306a36Sopenharmony_ci		t7xx_pcie_mac_set_int(t7xx_dev, int_type);
20562306a36Sopenharmony_ci	}
20662306a36Sopenharmony_ci}
20762306a36Sopenharmony_ci
20862306a36Sopenharmony_cistatic int t7xx_dpmaif_rxtx_sw_allocs(struct dpmaif_ctrl *dpmaif_ctrl)
20962306a36Sopenharmony_ci{
21062306a36Sopenharmony_ci	struct dpmaif_rx_queue *rx_q;
21162306a36Sopenharmony_ci	struct dpmaif_tx_queue *tx_q;
21262306a36Sopenharmony_ci	int ret, rx_idx, tx_idx, i;
21362306a36Sopenharmony_ci
21462306a36Sopenharmony_ci	ret = t7xx_dpmaif_bat_alloc(dpmaif_ctrl, &dpmaif_ctrl->bat_req, BAT_TYPE_NORMAL);
21562306a36Sopenharmony_ci	if (ret) {
21662306a36Sopenharmony_ci		dev_err(dpmaif_ctrl->dev, "Failed to allocate normal BAT table: %d\n", ret);
21762306a36Sopenharmony_ci		return ret;
21862306a36Sopenharmony_ci	}
21962306a36Sopenharmony_ci
22062306a36Sopenharmony_ci	ret = t7xx_dpmaif_bat_alloc(dpmaif_ctrl, &dpmaif_ctrl->bat_frag, BAT_TYPE_FRAG);
22162306a36Sopenharmony_ci	if (ret) {
22262306a36Sopenharmony_ci		dev_err(dpmaif_ctrl->dev, "Failed to allocate frag BAT table: %d\n", ret);
22362306a36Sopenharmony_ci		goto err_free_normal_bat;
22462306a36Sopenharmony_ci	}
22562306a36Sopenharmony_ci
22662306a36Sopenharmony_ci	for (rx_idx = 0; rx_idx < DPMAIF_RXQ_NUM; rx_idx++) {
22762306a36Sopenharmony_ci		rx_q = &dpmaif_ctrl->rxq[rx_idx];
22862306a36Sopenharmony_ci		rx_q->index = rx_idx;
22962306a36Sopenharmony_ci		rx_q->dpmaif_ctrl = dpmaif_ctrl;
23062306a36Sopenharmony_ci		ret = t7xx_dpmaif_rxq_init(rx_q);
23162306a36Sopenharmony_ci		if (ret)
23262306a36Sopenharmony_ci			goto err_free_rxq;
23362306a36Sopenharmony_ci	}
23462306a36Sopenharmony_ci
23562306a36Sopenharmony_ci	for (tx_idx = 0; tx_idx < DPMAIF_TXQ_NUM; tx_idx++) {
23662306a36Sopenharmony_ci		tx_q = &dpmaif_ctrl->txq[tx_idx];
23762306a36Sopenharmony_ci		tx_q->index = tx_idx;
23862306a36Sopenharmony_ci		tx_q->dpmaif_ctrl = dpmaif_ctrl;
23962306a36Sopenharmony_ci		ret = t7xx_dpmaif_txq_init(tx_q);
24062306a36Sopenharmony_ci		if (ret)
24162306a36Sopenharmony_ci			goto err_free_txq;
24262306a36Sopenharmony_ci	}
24362306a36Sopenharmony_ci
24462306a36Sopenharmony_ci	ret = t7xx_dpmaif_tx_thread_init(dpmaif_ctrl);
24562306a36Sopenharmony_ci	if (ret) {
24662306a36Sopenharmony_ci		dev_err(dpmaif_ctrl->dev, "Failed to start TX thread\n");
24762306a36Sopenharmony_ci		goto err_free_txq;
24862306a36Sopenharmony_ci	}
24962306a36Sopenharmony_ci
25062306a36Sopenharmony_ci	ret = t7xx_dpmaif_bat_rel_wq_alloc(dpmaif_ctrl);
25162306a36Sopenharmony_ci	if (ret)
25262306a36Sopenharmony_ci		goto err_thread_rel;
25362306a36Sopenharmony_ci
25462306a36Sopenharmony_ci	return 0;
25562306a36Sopenharmony_ci
25662306a36Sopenharmony_cierr_thread_rel:
25762306a36Sopenharmony_ci	t7xx_dpmaif_tx_thread_rel(dpmaif_ctrl);
25862306a36Sopenharmony_ci
25962306a36Sopenharmony_cierr_free_txq:
26062306a36Sopenharmony_ci	for (i = 0; i < tx_idx; i++) {
26162306a36Sopenharmony_ci		tx_q = &dpmaif_ctrl->txq[i];
26262306a36Sopenharmony_ci		t7xx_dpmaif_txq_free(tx_q);
26362306a36Sopenharmony_ci	}
26462306a36Sopenharmony_ci
26562306a36Sopenharmony_cierr_free_rxq:
26662306a36Sopenharmony_ci	for (i = 0; i < rx_idx; i++) {
26762306a36Sopenharmony_ci		rx_q = &dpmaif_ctrl->rxq[i];
26862306a36Sopenharmony_ci		t7xx_dpmaif_rxq_free(rx_q);
26962306a36Sopenharmony_ci	}
27062306a36Sopenharmony_ci
27162306a36Sopenharmony_ci	t7xx_dpmaif_bat_free(dpmaif_ctrl, &dpmaif_ctrl->bat_frag);
27262306a36Sopenharmony_ci
27362306a36Sopenharmony_cierr_free_normal_bat:
27462306a36Sopenharmony_ci	t7xx_dpmaif_bat_free(dpmaif_ctrl, &dpmaif_ctrl->bat_req);
27562306a36Sopenharmony_ci
27662306a36Sopenharmony_ci	return ret;
27762306a36Sopenharmony_ci}
27862306a36Sopenharmony_ci
27962306a36Sopenharmony_cistatic void t7xx_dpmaif_sw_release(struct dpmaif_ctrl *dpmaif_ctrl)
28062306a36Sopenharmony_ci{
28162306a36Sopenharmony_ci	struct dpmaif_rx_queue *rx_q;
28262306a36Sopenharmony_ci	struct dpmaif_tx_queue *tx_q;
28362306a36Sopenharmony_ci	int i;
28462306a36Sopenharmony_ci
28562306a36Sopenharmony_ci	t7xx_dpmaif_tx_thread_rel(dpmaif_ctrl);
28662306a36Sopenharmony_ci	t7xx_dpmaif_bat_wq_rel(dpmaif_ctrl);
28762306a36Sopenharmony_ci
28862306a36Sopenharmony_ci	for (i = 0; i < DPMAIF_TXQ_NUM; i++) {
28962306a36Sopenharmony_ci		tx_q = &dpmaif_ctrl->txq[i];
29062306a36Sopenharmony_ci		t7xx_dpmaif_txq_free(tx_q);
29162306a36Sopenharmony_ci	}
29262306a36Sopenharmony_ci
29362306a36Sopenharmony_ci	for (i = 0; i < DPMAIF_RXQ_NUM; i++) {
29462306a36Sopenharmony_ci		rx_q = &dpmaif_ctrl->rxq[i];
29562306a36Sopenharmony_ci		t7xx_dpmaif_rxq_free(rx_q);
29662306a36Sopenharmony_ci	}
29762306a36Sopenharmony_ci}
29862306a36Sopenharmony_ci
29962306a36Sopenharmony_cistatic int t7xx_dpmaif_start(struct dpmaif_ctrl *dpmaif_ctrl)
30062306a36Sopenharmony_ci{
30162306a36Sopenharmony_ci	struct dpmaif_hw_info *hw_info = &dpmaif_ctrl->hw_info;
30262306a36Sopenharmony_ci	struct dpmaif_hw_params hw_init_para;
30362306a36Sopenharmony_ci	struct dpmaif_rx_queue *rxq;
30462306a36Sopenharmony_ci	struct dpmaif_tx_queue *txq;
30562306a36Sopenharmony_ci	unsigned int buf_cnt;
30662306a36Sopenharmony_ci	int i, ret = 0;
30762306a36Sopenharmony_ci
30862306a36Sopenharmony_ci	if (dpmaif_ctrl->state == DPMAIF_STATE_PWRON)
30962306a36Sopenharmony_ci		return -EFAULT;
31062306a36Sopenharmony_ci
31162306a36Sopenharmony_ci	memset(&hw_init_para, 0, sizeof(hw_init_para));
31262306a36Sopenharmony_ci
31362306a36Sopenharmony_ci	for (i = 0; i < DPMAIF_RXQ_NUM; i++) {
31462306a36Sopenharmony_ci		rxq = &dpmaif_ctrl->rxq[i];
31562306a36Sopenharmony_ci		rxq->que_started = true;
31662306a36Sopenharmony_ci		rxq->index = i;
31762306a36Sopenharmony_ci		rxq->budget = rxq->bat_req->bat_size_cnt - 1;
31862306a36Sopenharmony_ci
31962306a36Sopenharmony_ci		hw_init_para.pkt_bat_base_addr[i] = rxq->bat_req->bat_bus_addr;
32062306a36Sopenharmony_ci		hw_init_para.pkt_bat_size_cnt[i] = rxq->bat_req->bat_size_cnt;
32162306a36Sopenharmony_ci		hw_init_para.pit_base_addr[i] = rxq->pit_bus_addr;
32262306a36Sopenharmony_ci		hw_init_para.pit_size_cnt[i] = rxq->pit_size_cnt;
32362306a36Sopenharmony_ci		hw_init_para.frg_bat_base_addr[i] = rxq->bat_frag->bat_bus_addr;
32462306a36Sopenharmony_ci		hw_init_para.frg_bat_size_cnt[i] = rxq->bat_frag->bat_size_cnt;
32562306a36Sopenharmony_ci	}
32662306a36Sopenharmony_ci
32762306a36Sopenharmony_ci	bitmap_zero(dpmaif_ctrl->bat_req.bat_bitmap, dpmaif_ctrl->bat_req.bat_size_cnt);
32862306a36Sopenharmony_ci	buf_cnt = dpmaif_ctrl->bat_req.bat_size_cnt - 1;
32962306a36Sopenharmony_ci	ret = t7xx_dpmaif_rx_buf_alloc(dpmaif_ctrl, &dpmaif_ctrl->bat_req, 0, buf_cnt, true);
33062306a36Sopenharmony_ci	if (ret) {
33162306a36Sopenharmony_ci		dev_err(dpmaif_ctrl->dev, "Failed to allocate RX buffer: %d\n", ret);
33262306a36Sopenharmony_ci		return ret;
33362306a36Sopenharmony_ci	}
33462306a36Sopenharmony_ci
33562306a36Sopenharmony_ci	buf_cnt = dpmaif_ctrl->bat_frag.bat_size_cnt - 1;
33662306a36Sopenharmony_ci	ret = t7xx_dpmaif_rx_frag_alloc(dpmaif_ctrl, &dpmaif_ctrl->bat_frag, buf_cnt, true);
33762306a36Sopenharmony_ci	if (ret) {
33862306a36Sopenharmony_ci		dev_err(dpmaif_ctrl->dev, "Failed to allocate frag RX buffer: %d\n", ret);
33962306a36Sopenharmony_ci		goto err_free_normal_bat;
34062306a36Sopenharmony_ci	}
34162306a36Sopenharmony_ci
34262306a36Sopenharmony_ci	for (i = 0; i < DPMAIF_TXQ_NUM; i++) {
34362306a36Sopenharmony_ci		txq = &dpmaif_ctrl->txq[i];
34462306a36Sopenharmony_ci		txq->que_started = true;
34562306a36Sopenharmony_ci
34662306a36Sopenharmony_ci		hw_init_para.drb_base_addr[i] = txq->drb_bus_addr;
34762306a36Sopenharmony_ci		hw_init_para.drb_size_cnt[i] = txq->drb_size_cnt;
34862306a36Sopenharmony_ci	}
34962306a36Sopenharmony_ci
35062306a36Sopenharmony_ci	ret = t7xx_dpmaif_hw_init(hw_info, &hw_init_para);
35162306a36Sopenharmony_ci	if (ret) {
35262306a36Sopenharmony_ci		dev_err(dpmaif_ctrl->dev, "Failed to initialize DPMAIF HW: %d\n", ret);
35362306a36Sopenharmony_ci		goto err_free_frag_bat;
35462306a36Sopenharmony_ci	}
35562306a36Sopenharmony_ci
35662306a36Sopenharmony_ci	ret = t7xx_dpmaif_dl_snd_hw_bat_cnt(hw_info, rxq->bat_req->bat_size_cnt - 1);
35762306a36Sopenharmony_ci	if (ret)
35862306a36Sopenharmony_ci		goto err_free_frag_bat;
35962306a36Sopenharmony_ci
36062306a36Sopenharmony_ci	ret = t7xx_dpmaif_dl_snd_hw_frg_cnt(hw_info, rxq->bat_frag->bat_size_cnt - 1);
36162306a36Sopenharmony_ci	if (ret)
36262306a36Sopenharmony_ci		goto err_free_frag_bat;
36362306a36Sopenharmony_ci
36462306a36Sopenharmony_ci	t7xx_dpmaif_ul_clr_all_intr(hw_info);
36562306a36Sopenharmony_ci	t7xx_dpmaif_dl_clr_all_intr(hw_info);
36662306a36Sopenharmony_ci	dpmaif_ctrl->state = DPMAIF_STATE_PWRON;
36762306a36Sopenharmony_ci	t7xx_dpmaif_enable_irq(dpmaif_ctrl);
36862306a36Sopenharmony_ci	wake_up(&dpmaif_ctrl->tx_wq);
36962306a36Sopenharmony_ci	return 0;
37062306a36Sopenharmony_ci
37162306a36Sopenharmony_cierr_free_frag_bat:
37262306a36Sopenharmony_ci	t7xx_dpmaif_bat_free(rxq->dpmaif_ctrl, rxq->bat_frag);
37362306a36Sopenharmony_ci
37462306a36Sopenharmony_cierr_free_normal_bat:
37562306a36Sopenharmony_ci	t7xx_dpmaif_bat_free(rxq->dpmaif_ctrl, rxq->bat_req);
37662306a36Sopenharmony_ci
37762306a36Sopenharmony_ci	return ret;
37862306a36Sopenharmony_ci}
37962306a36Sopenharmony_ci
38062306a36Sopenharmony_cistatic void t7xx_dpmaif_stop_sw(struct dpmaif_ctrl *dpmaif_ctrl)
38162306a36Sopenharmony_ci{
38262306a36Sopenharmony_ci	t7xx_dpmaif_tx_stop(dpmaif_ctrl);
38362306a36Sopenharmony_ci	t7xx_dpmaif_rx_stop(dpmaif_ctrl);
38462306a36Sopenharmony_ci}
38562306a36Sopenharmony_ci
38662306a36Sopenharmony_cistatic void t7xx_dpmaif_stop_hw(struct dpmaif_ctrl *dpmaif_ctrl)
38762306a36Sopenharmony_ci{
38862306a36Sopenharmony_ci	t7xx_dpmaif_hw_stop_all_txq(&dpmaif_ctrl->hw_info);
38962306a36Sopenharmony_ci	t7xx_dpmaif_hw_stop_all_rxq(&dpmaif_ctrl->hw_info);
39062306a36Sopenharmony_ci}
39162306a36Sopenharmony_ci
39262306a36Sopenharmony_cistatic int t7xx_dpmaif_stop(struct dpmaif_ctrl *dpmaif_ctrl)
39362306a36Sopenharmony_ci{
39462306a36Sopenharmony_ci	if (!dpmaif_ctrl->dpmaif_sw_init_done) {
39562306a36Sopenharmony_ci		dev_err(dpmaif_ctrl->dev, "dpmaif SW init fail\n");
39662306a36Sopenharmony_ci		return -EFAULT;
39762306a36Sopenharmony_ci	}
39862306a36Sopenharmony_ci
39962306a36Sopenharmony_ci	if (dpmaif_ctrl->state == DPMAIF_STATE_PWROFF)
40062306a36Sopenharmony_ci		return -EFAULT;
40162306a36Sopenharmony_ci
40262306a36Sopenharmony_ci	t7xx_dpmaif_disable_irq(dpmaif_ctrl);
40362306a36Sopenharmony_ci	dpmaif_ctrl->state = DPMAIF_STATE_PWROFF;
40462306a36Sopenharmony_ci	t7xx_dpmaif_stop_sw(dpmaif_ctrl);
40562306a36Sopenharmony_ci	t7xx_dpmaif_tx_clear(dpmaif_ctrl);
40662306a36Sopenharmony_ci	t7xx_dpmaif_rx_clear(dpmaif_ctrl);
40762306a36Sopenharmony_ci	return 0;
40862306a36Sopenharmony_ci}
40962306a36Sopenharmony_ci
41062306a36Sopenharmony_cistatic int t7xx_dpmaif_suspend(struct t7xx_pci_dev *t7xx_dev, void *param)
41162306a36Sopenharmony_ci{
41262306a36Sopenharmony_ci	struct dpmaif_ctrl *dpmaif_ctrl = param;
41362306a36Sopenharmony_ci
41462306a36Sopenharmony_ci	t7xx_dpmaif_tx_stop(dpmaif_ctrl);
41562306a36Sopenharmony_ci	t7xx_dpmaif_hw_stop_all_txq(&dpmaif_ctrl->hw_info);
41662306a36Sopenharmony_ci	t7xx_dpmaif_hw_stop_all_rxq(&dpmaif_ctrl->hw_info);
41762306a36Sopenharmony_ci	t7xx_dpmaif_disable_irq(dpmaif_ctrl);
41862306a36Sopenharmony_ci	t7xx_dpmaif_rx_stop(dpmaif_ctrl);
41962306a36Sopenharmony_ci	return 0;
42062306a36Sopenharmony_ci}
42162306a36Sopenharmony_ci
42262306a36Sopenharmony_cistatic void t7xx_dpmaif_unmask_dlq_intr(struct dpmaif_ctrl *dpmaif_ctrl)
42362306a36Sopenharmony_ci{
42462306a36Sopenharmony_ci	int qno;
42562306a36Sopenharmony_ci
42662306a36Sopenharmony_ci	for (qno = 0; qno < DPMAIF_RXQ_NUM; qno++)
42762306a36Sopenharmony_ci		t7xx_dpmaif_dlq_unmask_rx_done(&dpmaif_ctrl->hw_info, qno);
42862306a36Sopenharmony_ci}
42962306a36Sopenharmony_ci
43062306a36Sopenharmony_cistatic void t7xx_dpmaif_start_txrx_qs(struct dpmaif_ctrl *dpmaif_ctrl)
43162306a36Sopenharmony_ci{
43262306a36Sopenharmony_ci	struct dpmaif_rx_queue *rxq;
43362306a36Sopenharmony_ci	struct dpmaif_tx_queue *txq;
43462306a36Sopenharmony_ci	unsigned int que_cnt;
43562306a36Sopenharmony_ci
43662306a36Sopenharmony_ci	for (que_cnt = 0; que_cnt < DPMAIF_TXQ_NUM; que_cnt++) {
43762306a36Sopenharmony_ci		txq = &dpmaif_ctrl->txq[que_cnt];
43862306a36Sopenharmony_ci		txq->que_started = true;
43962306a36Sopenharmony_ci	}
44062306a36Sopenharmony_ci
44162306a36Sopenharmony_ci	for (que_cnt = 0; que_cnt < DPMAIF_RXQ_NUM; que_cnt++) {
44262306a36Sopenharmony_ci		rxq = &dpmaif_ctrl->rxq[que_cnt];
44362306a36Sopenharmony_ci		rxq->que_started = true;
44462306a36Sopenharmony_ci	}
44562306a36Sopenharmony_ci}
44662306a36Sopenharmony_ci
44762306a36Sopenharmony_cistatic int t7xx_dpmaif_resume(struct t7xx_pci_dev *t7xx_dev, void *param)
44862306a36Sopenharmony_ci{
44962306a36Sopenharmony_ci	struct dpmaif_ctrl *dpmaif_ctrl = param;
45062306a36Sopenharmony_ci
45162306a36Sopenharmony_ci	if (!dpmaif_ctrl)
45262306a36Sopenharmony_ci		return 0;
45362306a36Sopenharmony_ci
45462306a36Sopenharmony_ci	t7xx_dpmaif_start_txrx_qs(dpmaif_ctrl);
45562306a36Sopenharmony_ci	t7xx_dpmaif_enable_irq(dpmaif_ctrl);
45662306a36Sopenharmony_ci	t7xx_dpmaif_unmask_dlq_intr(dpmaif_ctrl);
45762306a36Sopenharmony_ci	t7xx_dpmaif_start_hw(&dpmaif_ctrl->hw_info);
45862306a36Sopenharmony_ci	wake_up(&dpmaif_ctrl->tx_wq);
45962306a36Sopenharmony_ci	return 0;
46062306a36Sopenharmony_ci}
46162306a36Sopenharmony_ci
46262306a36Sopenharmony_cistatic int t7xx_dpmaif_pm_entity_init(struct dpmaif_ctrl *dpmaif_ctrl)
46362306a36Sopenharmony_ci{
46462306a36Sopenharmony_ci	struct md_pm_entity *dpmaif_pm_entity = &dpmaif_ctrl->dpmaif_pm_entity;
46562306a36Sopenharmony_ci	int ret;
46662306a36Sopenharmony_ci
46762306a36Sopenharmony_ci	INIT_LIST_HEAD(&dpmaif_pm_entity->entity);
46862306a36Sopenharmony_ci	dpmaif_pm_entity->suspend = &t7xx_dpmaif_suspend;
46962306a36Sopenharmony_ci	dpmaif_pm_entity->suspend_late = NULL;
47062306a36Sopenharmony_ci	dpmaif_pm_entity->resume_early = NULL;
47162306a36Sopenharmony_ci	dpmaif_pm_entity->resume = &t7xx_dpmaif_resume;
47262306a36Sopenharmony_ci	dpmaif_pm_entity->id = PM_ENTITY_ID_DATA;
47362306a36Sopenharmony_ci	dpmaif_pm_entity->entity_param = dpmaif_ctrl;
47462306a36Sopenharmony_ci
47562306a36Sopenharmony_ci	ret = t7xx_pci_pm_entity_register(dpmaif_ctrl->t7xx_dev, dpmaif_pm_entity);
47662306a36Sopenharmony_ci	if (ret)
47762306a36Sopenharmony_ci		dev_err(dpmaif_ctrl->dev, "dpmaif register pm_entity fail\n");
47862306a36Sopenharmony_ci
47962306a36Sopenharmony_ci	return ret;
48062306a36Sopenharmony_ci}
48162306a36Sopenharmony_ci
48262306a36Sopenharmony_cistatic int t7xx_dpmaif_pm_entity_release(struct dpmaif_ctrl *dpmaif_ctrl)
48362306a36Sopenharmony_ci{
48462306a36Sopenharmony_ci	struct md_pm_entity *dpmaif_pm_entity = &dpmaif_ctrl->dpmaif_pm_entity;
48562306a36Sopenharmony_ci	int ret;
48662306a36Sopenharmony_ci
48762306a36Sopenharmony_ci	ret = t7xx_pci_pm_entity_unregister(dpmaif_ctrl->t7xx_dev, dpmaif_pm_entity);
48862306a36Sopenharmony_ci	if (ret < 0)
48962306a36Sopenharmony_ci		dev_err(dpmaif_ctrl->dev, "dpmaif register pm_entity fail\n");
49062306a36Sopenharmony_ci
49162306a36Sopenharmony_ci	return ret;
49262306a36Sopenharmony_ci}
49362306a36Sopenharmony_ci
49462306a36Sopenharmony_ciint t7xx_dpmaif_md_state_callback(struct dpmaif_ctrl *dpmaif_ctrl, enum md_state state)
49562306a36Sopenharmony_ci{
49662306a36Sopenharmony_ci	int ret = 0;
49762306a36Sopenharmony_ci
49862306a36Sopenharmony_ci	switch (state) {
49962306a36Sopenharmony_ci	case MD_STATE_WAITING_FOR_HS1:
50062306a36Sopenharmony_ci		ret = t7xx_dpmaif_start(dpmaif_ctrl);
50162306a36Sopenharmony_ci		break;
50262306a36Sopenharmony_ci
50362306a36Sopenharmony_ci	case MD_STATE_EXCEPTION:
50462306a36Sopenharmony_ci		ret = t7xx_dpmaif_stop(dpmaif_ctrl);
50562306a36Sopenharmony_ci		break;
50662306a36Sopenharmony_ci
50762306a36Sopenharmony_ci	case MD_STATE_STOPPED:
50862306a36Sopenharmony_ci		ret = t7xx_dpmaif_stop(dpmaif_ctrl);
50962306a36Sopenharmony_ci		break;
51062306a36Sopenharmony_ci
51162306a36Sopenharmony_ci	case MD_STATE_WAITING_TO_STOP:
51262306a36Sopenharmony_ci		t7xx_dpmaif_stop_hw(dpmaif_ctrl);
51362306a36Sopenharmony_ci		break;
51462306a36Sopenharmony_ci
51562306a36Sopenharmony_ci	default:
51662306a36Sopenharmony_ci		break;
51762306a36Sopenharmony_ci	}
51862306a36Sopenharmony_ci
51962306a36Sopenharmony_ci	return ret;
52062306a36Sopenharmony_ci}
52162306a36Sopenharmony_ci
52262306a36Sopenharmony_ci/**
52362306a36Sopenharmony_ci * t7xx_dpmaif_hif_init() - Initialize data path.
52462306a36Sopenharmony_ci * @t7xx_dev: MTK context structure.
52562306a36Sopenharmony_ci * @callbacks: Callbacks implemented by the network layer to handle RX skb and
52662306a36Sopenharmony_ci *	       event notifications.
52762306a36Sopenharmony_ci *
52862306a36Sopenharmony_ci * Allocate and initialize datapath control block.
52962306a36Sopenharmony_ci * Register datapath ISR, TX and RX resources.
53062306a36Sopenharmony_ci *
53162306a36Sopenharmony_ci * Return:
53262306a36Sopenharmony_ci * * dpmaif_ctrl pointer - Pointer to DPMAIF context structure.
53362306a36Sopenharmony_ci * * NULL		 - In case of error.
53462306a36Sopenharmony_ci */
53562306a36Sopenharmony_cistruct dpmaif_ctrl *t7xx_dpmaif_hif_init(struct t7xx_pci_dev *t7xx_dev,
53662306a36Sopenharmony_ci					 struct dpmaif_callbacks *callbacks)
53762306a36Sopenharmony_ci{
53862306a36Sopenharmony_ci	struct device *dev = &t7xx_dev->pdev->dev;
53962306a36Sopenharmony_ci	struct dpmaif_ctrl *dpmaif_ctrl;
54062306a36Sopenharmony_ci	int ret;
54162306a36Sopenharmony_ci
54262306a36Sopenharmony_ci	if (!callbacks)
54362306a36Sopenharmony_ci		return NULL;
54462306a36Sopenharmony_ci
54562306a36Sopenharmony_ci	dpmaif_ctrl = devm_kzalloc(dev, sizeof(*dpmaif_ctrl), GFP_KERNEL);
54662306a36Sopenharmony_ci	if (!dpmaif_ctrl)
54762306a36Sopenharmony_ci		return NULL;
54862306a36Sopenharmony_ci
54962306a36Sopenharmony_ci	dpmaif_ctrl->t7xx_dev = t7xx_dev;
55062306a36Sopenharmony_ci	dpmaif_ctrl->callbacks = callbacks;
55162306a36Sopenharmony_ci	dpmaif_ctrl->dev = dev;
55262306a36Sopenharmony_ci	dpmaif_ctrl->dpmaif_sw_init_done = false;
55362306a36Sopenharmony_ci	dpmaif_ctrl->hw_info.dev = dev;
55462306a36Sopenharmony_ci	dpmaif_ctrl->hw_info.pcie_base = t7xx_dev->base_addr.pcie_ext_reg_base -
55562306a36Sopenharmony_ci					 t7xx_dev->base_addr.pcie_dev_reg_trsl_addr;
55662306a36Sopenharmony_ci
55762306a36Sopenharmony_ci	ret = t7xx_dpmaif_pm_entity_init(dpmaif_ctrl);
55862306a36Sopenharmony_ci	if (ret)
55962306a36Sopenharmony_ci		return NULL;
56062306a36Sopenharmony_ci
56162306a36Sopenharmony_ci	t7xx_dpmaif_register_pcie_irq(dpmaif_ctrl);
56262306a36Sopenharmony_ci	t7xx_dpmaif_disable_irq(dpmaif_ctrl);
56362306a36Sopenharmony_ci
56462306a36Sopenharmony_ci	ret = t7xx_dpmaif_rxtx_sw_allocs(dpmaif_ctrl);
56562306a36Sopenharmony_ci	if (ret) {
56662306a36Sopenharmony_ci		t7xx_dpmaif_pm_entity_release(dpmaif_ctrl);
56762306a36Sopenharmony_ci		dev_err(dev, "Failed to allocate RX/TX SW resources: %d\n", ret);
56862306a36Sopenharmony_ci		return NULL;
56962306a36Sopenharmony_ci	}
57062306a36Sopenharmony_ci
57162306a36Sopenharmony_ci	dpmaif_ctrl->dpmaif_sw_init_done = true;
57262306a36Sopenharmony_ci	return dpmaif_ctrl;
57362306a36Sopenharmony_ci}
57462306a36Sopenharmony_ci
57562306a36Sopenharmony_civoid t7xx_dpmaif_hif_exit(struct dpmaif_ctrl *dpmaif_ctrl)
57662306a36Sopenharmony_ci{
57762306a36Sopenharmony_ci	if (dpmaif_ctrl->dpmaif_sw_init_done) {
57862306a36Sopenharmony_ci		t7xx_dpmaif_stop(dpmaif_ctrl);
57962306a36Sopenharmony_ci		t7xx_dpmaif_pm_entity_release(dpmaif_ctrl);
58062306a36Sopenharmony_ci		t7xx_dpmaif_sw_release(dpmaif_ctrl);
58162306a36Sopenharmony_ci		dpmaif_ctrl->dpmaif_sw_init_done = false;
58262306a36Sopenharmony_ci	}
58362306a36Sopenharmony_ci}
584